{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "460e18df",
      "metadata": {
        "id": "460e18df"
      },
      "source": [
        "# Warcraft Shortest Path"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "1ef0b563",
      "metadata": {
        "id": "1ef0b563",
        "outputId": "deb1cd53-2206-4769-e76b-2749bf0a186b"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Auto-Sklearn cannot be imported.\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<torch._C.Generator at 0x7f1ccc89a290>"
            ]
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "import time\n",
        "import random\n",
        "import pyepo\n",
        "import torch\n",
        "from torch import nn\n",
        "from matplotlib import pyplot as plt\n",
        "import numpy as np\n",
        "import pandas as pd\n",
        "import time\n",
        "from tqdm import tqdm\n",
        "from torch.utils.data import DataLoader, Dataset\n",
        "# fix random seed\n",
        "random.seed(135)\n",
        "np.random.seed(135)\n",
        "torch.manual_seed(135)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "22b83a43",
      "metadata": {
        "id": "22b83a43"
      },
      "source": [
        "## 1 Dataset"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0d022200",
      "metadata": {
        "id": "0d022200"
      },
      "source": [
        "We use the Warcraft terrains shortest paths [dataset](https://edmond.mpdl.mpg.de/dataset.xhtml?persistentId=doi:10.17617/3.YJCQ5S). Datasets were randomly generated from the Warcraft II [tileset](http://github.com/war2/war2edit) and used in Vlastelica, Marin, et al. \"Differentiation of Blackbox Combinatorial Solvers\". The Warcraft dataset is a captivating benchmark because the image input feature allows learning the shortest path from 10000 RGB terrains"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "8c4791e8",
      "metadata": {
        "id": "8c4791e8"
      },
      "outputs": [],
      "source": [
        "# map size\n",
        "k = 12"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7d8353b0",
      "metadata": {
        "id": "7d8353b0"
      },
      "source": [
        "### 1.1 Maps"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "a344ab63",
      "metadata": {
        "id": "a344ab63"
      },
      "outputs": [],
      "source": [
        "tmaps_train = np.load(\"./raw_data/{}x{}/train_maps.npy\".format(k,k))\n",
        "#tmaps_val = np.load(\"../data/warcraft_shortest_path_oneskin/{}x{}/val_maps.npy\".format(k,k))\n",
        "tmaps_test = np.load(\"./raw_data/{}x{}/test_maps.npy\".format(k,k))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b903781d",
      "metadata": {
        "id": "b903781d"
      },
      "source": [
        "### 1.2 Costs"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "67ce1279",
      "metadata": {
        "id": "67ce1279"
      },
      "outputs": [],
      "source": [
        "costs_train = np.load(\"./raw_data/{}x{}/train_vertex_weights.npy\".format(k,k))\n",
        "#costs_val = np.load(\"../data/warcraft_shortest_path_oneskin/{}x{}/val_vertex_weights.npy\".format(k,k))\n",
        "costs_test = np.load(\"./raw_data/{}x{}/test_vertex_weights.npy\".format(k,k))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "60940432",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[[0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 1.2 1.2 1.2 0.8]\n",
            " [0.8 0.8 0.8 0.8 0.8 1.2 1.2 1.2 1.2 9.2 1.2 1.2]\n",
            " [0.8 0.8 0.8 1.2 1.2 1.2 1.2 1.2 1.2 1.2 1.2 1.2]\n",
            " [1.2 0.8 0.8 1.2 1.2 0.8 1.2 1.2 7.7 7.7 1.2 1.2]\n",
            " [1.2 0.8 1.2 1.2 0.8 0.8 0.8 1.2 1.2 7.7 1.2 1.2]\n",
            " [1.2 0.8 1.2 1.2 0.8 0.8 0.8 0.8 1.2 7.7 1.2 1.2]\n",
            " [1.2 0.8 1.2 1.2 1.2 0.8 0.8 1.2 1.2 1.2 7.7 7.7]\n",
            " [0.8 0.8 1.2 1.2 0.8 0.8 1.2 0.8 0.8 1.2 7.7 7.7]\n",
            " [0.8 0.8 1.2 1.2 1.2 1.2 1.2 1.2 1.2 1.2 7.7 7.7]\n",
            " [0.8 0.8 1.2 9.2 9.2 9.2 9.2 1.2 1.2 7.7 7.7 7.7]\n",
            " [0.8 0.8 1.2 9.2 9.2 9.2 9.2 1.2 1.2 7.7 7.7 7.7]\n",
            " [0.8 0.8 1.2 9.2 9.2 9.2 9.2 1.2 1.2 1.2 7.7 7.7]]\n"
          ]
        }
      ],
      "source": [
        "print(costs_train[0,:,:])"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b723276c",
      "metadata": {
        "id": "b723276c"
      },
      "source": [
        "### 1.3 Paths"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "87438df2",
      "metadata": {
        "id": "87438df2"
      },
      "outputs": [],
      "source": [
        "paths_train = np.load(\"./raw_data/{}x{}/train_shortest_paths.npy\".format(k,k))\n",
        "#paths_val = np.load(\"../data/warcraft_shortest_path_oneskin/{}x{}/val_shortest_paths.npy\".format(k,k))\n",
        "paths_test = np.load(\"./raw_data/{}x{}/test_shortest_paths.npy\".format(k,k))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "955b3261",
      "metadata": {},
      "outputs": [
        {
          "ename": "FileNotFoundError",
          "evalue": "[Errno 2] No such file or directory: '.imgs/warcraft_cost_matrix_0.pdf'",
          "output_type": "error",
          "traceback": [
            "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
            "\u001b[0;31mFileNotFoundError\u001b[0m                         Traceback (most recent call last)",
            "Cell \u001b[0;32mIn[6], line 4\u001b[0m\n\u001b[1;32m      2\u001b[0m plt\u001b[38;5;241m.\u001b[39maxis(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124moff\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m      3\u001b[0m plt\u001b[38;5;241m.\u001b[39mimshow(costs_train[\u001b[38;5;241m0\u001b[39m])\n\u001b[0;32m----> 4\u001b[0m \u001b[43mplt\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msavefig\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43m.imgs/warcraft_cost_matrix_0.pdf\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[1;32m      5\u001b[0m plt\u001b[38;5;241m.\u001b[39mclose()\n\u001b[1;32m      7\u001b[0m plt\u001b[38;5;241m.\u001b[39maxis(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124moff\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n",
            "File \u001b[0;32m~/Research/Implicit-Networks/Environments/fpo-dys-env/lib/python3.8/site-packages/matplotlib/pyplot.py:1023\u001b[0m, in \u001b[0;36msavefig\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m   1020\u001b[0m \u001b[38;5;129m@_copy_docstring_and_deprecators\u001b[39m(Figure\u001b[38;5;241m.\u001b[39msavefig)\n\u001b[1;32m   1021\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21msavefig\u001b[39m(\u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs):\n\u001b[1;32m   1022\u001b[0m     fig \u001b[38;5;241m=\u001b[39m gcf()\n\u001b[0;32m-> 1023\u001b[0m     res \u001b[38;5;241m=\u001b[39m \u001b[43mfig\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msavefig\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m   1024\u001b[0m     fig\u001b[38;5;241m.\u001b[39mcanvas\u001b[38;5;241m.\u001b[39mdraw_idle()  \u001b[38;5;66;03m# Need this if 'transparent=True', to reset colors.\u001b[39;00m\n\u001b[1;32m   1025\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m res\n",
            "File \u001b[0;32m~/Research/Implicit-Networks/Environments/fpo-dys-env/lib/python3.8/site-packages/matplotlib/figure.py:3378\u001b[0m, in \u001b[0;36mFigure.savefig\u001b[0;34m(self, fname, transparent, **kwargs)\u001b[0m\n\u001b[1;32m   3374\u001b[0m     \u001b[38;5;28;01mfor\u001b[39;00m ax \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39maxes:\n\u001b[1;32m   3375\u001b[0m         stack\u001b[38;5;241m.\u001b[39menter_context(\n\u001b[1;32m   3376\u001b[0m             ax\u001b[38;5;241m.\u001b[39mpatch\u001b[38;5;241m.\u001b[39m_cm_set(facecolor\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mnone\u001b[39m\u001b[38;5;124m'\u001b[39m, edgecolor\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mnone\u001b[39m\u001b[38;5;124m'\u001b[39m))\n\u001b[0;32m-> 3378\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcanvas\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mprint_figure\u001b[49m\u001b[43m(\u001b[49m\u001b[43mfname\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n",
            "File \u001b[0;32m~/Research/Implicit-Networks/Environments/fpo-dys-env/lib/python3.8/site-packages/matplotlib/backend_bases.py:2366\u001b[0m, in \u001b[0;36mFigureCanvasBase.print_figure\u001b[0;34m(self, filename, dpi, facecolor, edgecolor, orientation, format, bbox_inches, pad_inches, bbox_extra_artists, backend, **kwargs)\u001b[0m\n\u001b[1;32m   2362\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m   2363\u001b[0m     \u001b[38;5;66;03m# _get_renderer may change the figure dpi (as vector formats\u001b[39;00m\n\u001b[1;32m   2364\u001b[0m     \u001b[38;5;66;03m# force the figure dpi to 72), so we need to set it again here.\u001b[39;00m\n\u001b[1;32m   2365\u001b[0m     \u001b[38;5;28;01mwith\u001b[39;00m cbook\u001b[38;5;241m.\u001b[39m_setattr_cm(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mfigure, dpi\u001b[38;5;241m=\u001b[39mdpi):\n\u001b[0;32m-> 2366\u001b[0m         result \u001b[38;5;241m=\u001b[39m \u001b[43mprint_method\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m   2367\u001b[0m \u001b[43m            \u001b[49m\u001b[43mfilename\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m   2368\u001b[0m \u001b[43m            \u001b[49m\u001b[43mfacecolor\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mfacecolor\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m   2369\u001b[0m \u001b[43m            \u001b[49m\u001b[43medgecolor\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43medgecolor\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m   2370\u001b[0m \u001b[43m            \u001b[49m\u001b[43morientation\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43morientation\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m   2371\u001b[0m \u001b[43m            \u001b[49m\u001b[43mbbox_inches_restore\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m_bbox_inches_restore\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m   2372\u001b[0m \u001b[43m            \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m   2373\u001b[0m \u001b[38;5;28;01mfinally\u001b[39;00m:\n\u001b[1;32m   2374\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m bbox_inches \u001b[38;5;129;01mand\u001b[39;00m restore_bbox:\n",
            "File \u001b[0;32m~/Research/Implicit-Networks/Environments/fpo-dys-env/lib/python3.8/site-packages/matplotlib/backend_bases.py:2232\u001b[0m, in \u001b[0;36mFigureCanvasBase._switch_canvas_and_return_print_method.<locals>.<lambda>\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m   2228\u001b[0m     optional_kws \u001b[38;5;241m=\u001b[39m {  \u001b[38;5;66;03m# Passed by print_figure for other renderers.\u001b[39;00m\n\u001b[1;32m   2229\u001b[0m         \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdpi\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mfacecolor\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124medgecolor\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124morientation\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m   2230\u001b[0m         \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mbbox_inches_restore\u001b[39m\u001b[38;5;124m\"\u001b[39m}\n\u001b[1;32m   2231\u001b[0m     skip \u001b[38;5;241m=\u001b[39m optional_kws \u001b[38;5;241m-\u001b[39m {\u001b[38;5;241m*\u001b[39minspect\u001b[38;5;241m.\u001b[39msignature(meth)\u001b[38;5;241m.\u001b[39mparameters}\n\u001b[0;32m-> 2232\u001b[0m     print_method \u001b[38;5;241m=\u001b[39m functools\u001b[38;5;241m.\u001b[39mwraps(meth)(\u001b[38;5;28;01mlambda\u001b[39;00m \u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: \u001b[43mmeth\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m   2233\u001b[0m \u001b[43m        \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43m{\u001b[49m\u001b[43mk\u001b[49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mv\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mfor\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mk\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mv\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01min\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mkwargs\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mitems\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mif\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mk\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01mnot\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;129;43;01min\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mskip\u001b[49m\u001b[43m}\u001b[49m\u001b[43m)\u001b[49m)\n\u001b[1;32m   2234\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:  \u001b[38;5;66;03m# Let third-parties do as they see fit.\u001b[39;00m\n\u001b[1;32m   2235\u001b[0m     print_method \u001b[38;5;241m=\u001b[39m meth\n",
            "File \u001b[0;32m~/Research/Implicit-Networks/Environments/fpo-dys-env/lib/python3.8/site-packages/matplotlib/backends/backend_pdf.py:2813\u001b[0m, in \u001b[0;36mFigureCanvasPdf.print_pdf\u001b[0;34m(self, filename, bbox_inches_restore, metadata)\u001b[0m\n\u001b[1;32m   2811\u001b[0m     file \u001b[38;5;241m=\u001b[39m filename\u001b[38;5;241m.\u001b[39m_file\n\u001b[1;32m   2812\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m-> 2813\u001b[0m     file \u001b[38;5;241m=\u001b[39m \u001b[43mPdfFile\u001b[49m\u001b[43m(\u001b[49m\u001b[43mfilename\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmetadata\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmetadata\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m   2814\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m   2815\u001b[0m     file\u001b[38;5;241m.\u001b[39mnewPage(width, height)\n",
            "File \u001b[0;32m~/Research/Implicit-Networks/Environments/fpo-dys-env/lib/python3.8/site-packages/matplotlib/backends/backend_pdf.py:714\u001b[0m, in \u001b[0;36mPdfFile.__init__\u001b[0;34m(self, filename, metadata)\u001b[0m\n\u001b[1;32m    712\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39moriginal_file_like \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[1;32m    713\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mtell_base \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m0\u001b[39m\n\u001b[0;32m--> 714\u001b[0m fh, opened \u001b[38;5;241m=\u001b[39m \u001b[43mcbook\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mto_filehandle\u001b[49m\u001b[43m(\u001b[49m\u001b[43mfilename\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mwb\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mreturn_opened\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m)\u001b[49m\n\u001b[1;32m    715\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m opened:\n\u001b[1;32m    716\u001b[0m     \u001b[38;5;28;01mtry\u001b[39;00m:\n",
            "File \u001b[0;32m~/Research/Implicit-Networks/Environments/fpo-dys-env/lib/python3.8/site-packages/matplotlib/cbook/__init__.py:494\u001b[0m, in \u001b[0;36mto_filehandle\u001b[0;34m(fname, flag, return_opened, encoding)\u001b[0m\n\u001b[1;32m    492\u001b[0m         fh \u001b[38;5;241m=\u001b[39m bz2\u001b[38;5;241m.\u001b[39mBZ2File(fname, flag)\n\u001b[1;32m    493\u001b[0m     \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m--> 494\u001b[0m         fh \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mopen\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mfname\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mflag\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mencoding\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mencoding\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    495\u001b[0m     opened \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mTrue\u001b[39;00m\n\u001b[1;32m    496\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m \u001b[38;5;28mhasattr\u001b[39m(fname, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mseek\u001b[39m\u001b[38;5;124m'\u001b[39m):\n",
            "\u001b[0;31mFileNotFoundError\u001b[0m: [Errno 2] No such file or directory: '.imgs/warcraft_cost_matrix_0.pdf'"
          ]
        },
        {
          "data": {
            "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYUAAAGFCAYAAAASI+9IAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8pXeV/AAAACXBIWXMAAA9hAAAPYQGoP6dpAAAF+0lEQVR4nO3XsY3jBhBAUd2JDbCBbWBr2ECBk81dpfNLLlCgGq4BNcAKZDn7cLA+b7IaAnovJjAjisDHfLvf7/cDABwOh+/TCwCwH6IAQEQBgIgCABEFACIKAEQUAIgoAJDlsw/+8f3Pr9wDGHJc1+kVnspt28Zm//z7r/99xqUAQEQBgIgCABEFACIKAEQUAIgoABBRACCiAEBEAYCIAgARBQAiCgBEFACIKAAQUQAgogBARAGAiAIAEQUAIgoARBQAiCgAEFEAIKIAQEQBgIgCABEFACIKAEQUAMgyvQD823Fdp1fgQX78Oo/Nfn89jc3e+zfuUgAgogBARAGAiAIAEQUAIgoARBQAiCgAEFEAIKIAQEQBgIgCABEFACIKAEQUAIgoABBRACCiAEBEAYCIAgARBQAiCgBEFACIKAAQUQAgogBARAGAiAIAEQUAIgoAZJlegI8d13V6BfhS76+n6RX4gEsBgIgCABEFACIKAEQUAIgoABBRACCiAEBEAYCIAgARBQAiCgBEFACIKAAQUQAgogBARAGAiAIAEQUAIgoARBQAiCgAEFEAIKIAQEQBgIgCABEFACIKAEQUAMjy2QeP6/qVe/zWbdvGZvNYk//15Dc+6XS5Tq/wcOe3l+kVdsulAEBEAYCIAgARBQAiCgBEFACIKAAQUQAgogBARAGAiAIAEQUAIgoARBQAiCgAEFEAIKIAQEQBgIgCABEFACIKAEQUAIgoABBRACCiAEBEAYCIAgARBQAiCgBEFADIMr3A3h3XdXqFh7tt2/QKIyZ/9+R3dn57GZl7ulxH5vJ7LgUAIgoARBQAiCgAEFEAIKIAQEQBgIgCABEFACIKAEQUAIgoABBRACCiAEBEAYCIAgARBQAiCgBEFACIKAAQUQAgogBARAGAiAIAEQUAIgoARBQAiCgAEFEAIKIAQJbpBYDD4bZtY7OP6zo2m/1xKQAQUQAgogBARAGAiAIAEQUAIgoARBQAiCgAEFEAIKIAQEQBgIgCABEFACIKAEQUAIgoABBRACCiAEBEAYCIAgARBQAiCgBEFACIKAAQUQAgogBARAGAiAIAEQUAskwvwP4c13Vs9m3bxmZPmnznU85vL2OzT5fr2Oy9cykAEFEAIKIAQEQBgIgCABEFACIKAEQUAIgoABBRACCiAEBEAYCIAgARBQAiCgBEFACIKAAQUQAgogBARAGAiAIAEQUAIgoARBQAiCgAEFEAIKIAQEQBgIgCABEFALJ89sHbtn3lHuzIs/7Xx3Udm/2M73zyffPfXAoARBQAiCgAEFEAIKIAQEQBgIgCABEFACIKAEQUAIgoABBRACCiAEBEAYCIAgARBQAiCgBEFACIKAAQUQAgogBARAGAiAIAEQUAIgoARBQAiCgAEFEAIKIAQEQBgCzTC7A/x3WdXuHpeOfshUsBgIgCABEFACIKAEQUAIgoABBRACCiAEBEAYCIAgARBQAiCgBEFACIKAAQUQAgogBARAGAiAIAEQUAIgoARBQAiCgAEFEAIKIAQEQBgIgCABEFACIKAEQUAMgyvQAf+/HrPL0CD/T+eppe4eFOl+v0CnzApQBARAGAiAIAEQUAIgoARBQAiCgAEFEAIKIAQEQBgIgCABEFACIKAEQUAIgoABBRACCiAEBEAYCIAgARBQAiCgBEFACIKAAQUQAgogBARAGAiAIAEQUAIgoARBQAiCgAEFEAIKIAQEQBgIgCABEFACIKAEQUAIgoABBRACCiAEBEAYCIAgARBQAiCgBEFACIKAAQUQAgogBARAGAiAIAEQUAIgoARBQAiCgAEFEAIKIAQEQBgIgCABEFACIKAGSZXgB4Tue3l7HZp8t1bPbeuRQAiCgAEFEAIKIAQEQBgIgCABEFACIKAEQUAIgoABBRACCiAEBEAYCIAgARBQAiCgBEFACIKAAQUQAgogBARAGAiAIAEQUAIgoARBQAiCgAEFEAIKIAQEQBgIgCAPl2v9/v00sAsA8uBQAiCgBEFACIKAAQUQAgogBARAGAiAIAEQUA8g9GQEFsp5Rp/wAAAABJRU5ErkJggg==",
            "text/plain": [
              "<Figure size 640x480 with 1 Axes>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "# plot some cost matrices\n",
        "plt.axis(\"off\")\n",
        "plt.imshow(costs_train[0])\n",
        "plt.savefig('.imgs/warcraft_cost_matrix_0.pdf')\n",
        "plt.close()\n",
        "\n",
        "plt.axis(\"off\")\n",
        "plt.imshow(costs_train[27])\n",
        "plt.savefig('.imgs/warcraft_cost_matrix_1.pdf')\n",
        "plt.close()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3e83d132",
      "metadata": {
        "id": "3e83d132"
      },
      "source": [
        "## 2 Data Loader"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "0271d7a2",
      "metadata": {
        "id": "0271d7a2"
      },
      "outputs": [],
      "source": [
        "class mapDataset(Dataset):\n",
        "    def __init__(self, tmaps, costs, paths):\n",
        "        self.tmaps = tmaps\n",
        "        self.costs = costs\n",
        "        self.paths = paths\n",
        "        self.objs = (costs * paths).sum(axis=(1,2)).reshape(-1,1)\n",
        "\n",
        "    def __len__(self):\n",
        "        return len(self.costs)\n",
        "\n",
        "    def __getitem__(self, ind):\n",
        "        return (\n",
        "            torch.FloatTensor(self.tmaps[ind].transpose(2, 0, 1)/255).detach(), # image\n",
        "            torch.FloatTensor(self.costs[ind]).reshape(-1),\n",
        "            torch.FloatTensor(self.paths[ind]).reshape(-1),\n",
        "            torch.FloatTensor(self.objs[ind]),\n",
        "        )"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "2b71596c",
      "metadata": {
        "id": "2b71596c"
      },
      "outputs": [],
      "source": [
        "# datasets\n",
        "dataset_train = mapDataset(tmaps_train, costs_train, paths_train)\n",
        "#dataset_val = mapDataset(tmaps_val, costs_val, paths_val)\n",
        "dataset_test = mapDataset(tmaps_test, costs_test, paths_test)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "078a1328",
      "metadata": {
        "id": "078a1328"
      },
      "outputs": [],
      "source": [
        "# dataloader\n",
        "batch_size = 70\n",
        "loader_train = DataLoader(dataset_train, batch_size=batch_size, shuffle=True)\n",
        "#loader_val = DataLoader(dataset_val, batch_size=batch_size, shuffle=False)\n",
        "loader_test = DataLoader(dataset_test, batch_size=batch_size, shuffle=False)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c190c011",
      "metadata": {
        "id": "c190c011"
      },
      "source": [
        "## 3 Neural Network: Truncated Resnet18"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ef5b1f76",
      "metadata": {
        "id": "ef5b1f76"
      },
      "source": [
        "Same as previous paper, we used the truncated ResNet18 (first five layers), $50$ epochs with batches of size $70$, learning rate $0.0005$ decaying at the epochs $30$ and $40$, and $n = 1, \\sigma = 1$."
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0db14ca5",
      "metadata": {
        "id": "0db14ca5"
      },
      "source": [
        "### 3.2 Truncated Resnet18"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "77008efd",
      "metadata": {
        "id": "77008efd"
      },
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "/home/daniel/Research/Implicit-Networks/Environments/fpo-dys-env/lib/python3.8/site-packages/torchvision/models/_utils.py:208: UserWarning: The parameter 'pretrained' is deprecated since 0.13 and may be removed in the future, please use 'weights' instead.\n",
            "  warnings.warn(\n",
            "/home/daniel/Research/Implicit-Networks/Environments/fpo-dys-env/lib/python3.8/site-packages/torchvision/models/_utils.py:223: UserWarning: Arguments other than a weight enum or `None` for 'weights' are deprecated since 0.13 and may be removed in the future. The current behavior is equivalent to passing `weights=None`.\n",
            "  warnings.warn(msg)\n"
          ]
        }
      ],
      "source": [
        "from torchvision.models import resnet18\n",
        "nnet = resnet18(pretrained=False)\n",
        "# build new ResNet18 with Max Pooling\n",
        "class partialResNet(nn.Module):\n",
        "\n",
        "    def __init__(self, k):\n",
        "        super(partialResNet, self).__init__()\n",
        "        # init resnet 18\n",
        "        resnet = resnet18(pretrained=False)\n",
        "        # first five layers of ResNet18\n",
        "        self.conv1 = resnet.conv1\n",
        "        self.bn = resnet.bn1\n",
        "        self.relu = resnet.relu\n",
        "        self.maxpool1 = resnet.maxpool\n",
        "        self.block = resnet.layer1\n",
        "        # conv to 1 channel\n",
        "        self.conv2  = nn.Conv2d(64, 1, kernel_size=(1, 1), stride=(1, 1), padding=(1, 1), bias=False)\n",
        "        # max pooling\n",
        "        self.maxpool2 = nn.AdaptiveMaxPool2d((k,k))\n",
        "\n",
        "    def forward(self, x):\n",
        "        h = self.conv1(x)\n",
        "        h = self.bn(h)\n",
        "        h = self.relu(h)\n",
        "        h = self.maxpool1(h)\n",
        "        h = self.block(h)\n",
        "        h = self.conv2(h)\n",
        "        out = self.maxpool2(h)\n",
        "        # reshape for optmodel\n",
        "        out = torch.squeeze(out, 1)\n",
        "        out = out.reshape(out.shape[0], -1)\n",
        "        return out"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "fee41336",
      "metadata": {
        "id": "fee41336"
      },
      "source": [
        "### 3.3 Hyperparameters"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "id": "60971dbc",
      "metadata": {
        "id": "60971dbc"
      },
      "outputs": [],
      "source": [
        "# number of epochs\n",
        "epochs = 50\n",
        "# learning rate\n",
        "lr = 5e-4\n",
        "# log step\n",
        "log_step = 1"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "bbf12ea4",
      "metadata": {
        "id": "bbf12ea4"
      },
      "source": [
        "## 4 Optimization Model: Linear Programming"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "74d187f0",
      "metadata": {
        "id": "74d187f0"
      },
      "outputs": [],
      "source": [
        "import gurobipy as gp\n",
        "from gurobipy import GRB\n",
        "\n",
        "from pyepo.model.grb.grbmodel import optGrbModel\n",
        "\n",
        "class shortestPathModel(optGrbModel):\n",
        "    \"\"\"\n",
        "    This class is optimization model for shortest path problem on 2D grid with 8 neighbors\n",
        "\n",
        "    Attributes:\n",
        "        _model (GurobiPy model): Gurobi model\n",
        "        grid (tuple of int): Size of grid network\n",
        "        nodes (list): list of vertex\n",
        "        edges (list): List of arcs\n",
        "        nodes_map (ndarray): 2D array for node index\n",
        "    \"\"\"\n",
        "\n",
        "    def __init__(self, grid):\n",
        "        \"\"\"\n",
        "        Args:\n",
        "            grid (tuple of int): size of grid network\n",
        "        \"\"\"\n",
        "        self.grid = grid\n",
        "        self.nodes, self.edges, self.nodes_map = self._getEdges()\n",
        "        super().__init__()\n",
        "\n",
        "    def _getEdges(self):\n",
        "        \"\"\"\n",
        "        A method to get list of edges for grid network\n",
        "\n",
        "        Returns:\n",
        "            list: arcs\n",
        "        \"\"\"\n",
        "        # init list\n",
        "        nodes, edges = [], []\n",
        "        # init map from coord to ind\n",
        "        nodes_map = {}\n",
        "        for i in range(self.grid[0]):\n",
        "            for j in range(self.grid[1]):\n",
        "                u = self._calNode(i, j)\n",
        "                nodes_map[u] = (i,j)\n",
        "                nodes.append(u)\n",
        "                # edge to 8 neighbors\n",
        "                # up\n",
        "                if i != 0:\n",
        "                    v = self._calNode(i-1, j)\n",
        "                    edges.append((u,v))\n",
        "                    # up-right\n",
        "                    if j != self.grid[1] - 1:\n",
        "                        v = self._calNode(i-1, j+1)\n",
        "                        edges.append((u,v))\n",
        "                # right\n",
        "                if j != self.grid[1] - 1:\n",
        "                    v = self._calNode(i, j+1)\n",
        "                    edges.append((u,v))\n",
        "                    # down-right\n",
        "                    if i != self.grid[0] - 1:\n",
        "                        v = self._calNode(i+1, j+1)\n",
        "                        edges.append((u,v))\n",
        "                # down\n",
        "                if i != self.grid[0] - 1:\n",
        "                    v = self._calNode(i+1, j)\n",
        "                    edges.append((u,v))\n",
        "                    # down-left\n",
        "                    if j != 0:\n",
        "                        v = self._calNode(i+1, j-1)\n",
        "                        edges.append((u,v))\n",
        "                # left\n",
        "                if j != 0:\n",
        "                    v = self._calNode(i, j-1)\n",
        "                    edges.append((u,v))\n",
        "                    # top-left\n",
        "                    if i != 0:\n",
        "                        v = self._calNode(i-1, j-1)\n",
        "                        edges.append((u,v))\n",
        "        return nodes, edges, nodes_map\n",
        "\n",
        "    def _calNode(self, x, y):\n",
        "        \"\"\"\n",
        "        A method to calculate index of node\n",
        "        \"\"\"\n",
        "        v = x * self.grid[1] + y\n",
        "        return v\n",
        "\n",
        "    def _getModel(self):\n",
        "        \"\"\"\n",
        "        A method to build Gurobi model\n",
        "\n",
        "        Returns:\n",
        "            tuple: optimization model and variables\n",
        "        \"\"\"\n",
        "        # ceate a model\n",
        "        m = gp.Model(\"shortest path\")\n",
        "        # varibles\n",
        "        x = m.addVars(self.edges, ub=1, name=\"x\")\n",
        "        # sense\n",
        "        m.modelSense = GRB.MINIMIZE\n",
        "        # constraints\n",
        "        for i in range(self.grid[0]):\n",
        "            for j in range(self.grid[1]):\n",
        "                v = self._calNode(i, j)\n",
        "                expr = 0\n",
        "                for e in self.edges:\n",
        "                    # flow in\n",
        "                    if v == e[1]:\n",
        "                        expr += x[e]\n",
        "                    # flow out\n",
        "                    elif v == e[0]:\n",
        "                        expr -= x[e]\n",
        "                # source\n",
        "                if i == 0 and j == 0:\n",
        "                    m.addConstr(expr == -1)\n",
        "                # sink\n",
        "                elif i == self.grid[0] - 1 and j == self.grid[0] - 1:\n",
        "                    m.addConstr(expr == 1)\n",
        "                # transition\n",
        "                else:\n",
        "                    m.addConstr(expr == 0)\n",
        "        return m, x\n",
        "\n",
        "    def setObj(self, c):\n",
        "        \"\"\"\n",
        "        A method to set objective function\n",
        "\n",
        "        Args:\n",
        "            c (np.ndarray): cost of objective function\n",
        "        \"\"\"\n",
        "        # vector to matrix\n",
        "        c = c.reshape(self.grid)\n",
        "        # sum up vector cost\n",
        "        obj = c[0,0] + gp.quicksum(c[self.nodes_map[j]] * self.x[i,j] for i, j in self.x)\n",
        "        self._model.setObjective(obj)\n",
        "\n",
        "    def solve(self):\n",
        "        \"\"\"\n",
        "        A method to solve model\n",
        "\n",
        "        Returns:\n",
        "            tuple: optimal solution (list) and objective value (float)\n",
        "        \"\"\"\n",
        "        # update gurobi model\n",
        "        self._model.update()\n",
        "        # solve\n",
        "        self._model.optimize()\n",
        "        # kxk solution map\n",
        "        sol = np.zeros(self.grid)\n",
        "        for i, j in self.edges:\n",
        "            # active edge\n",
        "            if abs(1 - self.x[i,j].x) < 1e-3:\n",
        "                # node on active edge\n",
        "                sol[self.nodes_map[i]] = 1\n",
        "                sol[self.nodes_map[j]] = 1\n",
        "        # matrix to vector\n",
        "        sol = sol.reshape(-1)\n",
        "        return sol, self._model.objVal"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "id": "0b685b7a",
      "metadata": {
        "id": "0b685b7a",
        "outputId": "751e0639-fd0f-4048-a522-98e23a8c0fc0"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Set parameter Username\n",
            "Academic license - for non-commercial use only - expires 2025-02-22\n"
          ]
        }
      ],
      "source": [
        "# init model\n",
        "grid = (k, k)\n",
        "optmodel = shortestPathModel(grid)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c4f6fee6",
      "metadata": {
        "id": "c4f6fee6"
      },
      "source": [
        "## 5 Useful Functions"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "id": "f6f668ec",
      "metadata": {
        "id": "f6f668ec"
      },
      "outputs": [],
      "source": [
        "def evaluate(nnet, optmodel, dataloader):\n",
        "    # init data\n",
        "    data = {\"Regret\":[], \"Relative Regret\":[], \"Accuracy\":[], \"Optimal\":[]}\n",
        "    # eval\n",
        "    nnet.eval()\n",
        "    for x, c, w, z in tqdm(dataloader):\n",
        "        # cuda\n",
        "        if next(nnet.parameters()).is_cuda:\n",
        "            x, c, w, z = x.cuda(), c.cuda(), w.cuda(), z.cuda()\n",
        "        # predict\n",
        "        cp = nnet(x)\n",
        "        # to numpy\n",
        "        c = c.to(\"cpu\").detach().numpy()\n",
        "        w = w.to(\"cpu\").detach().numpy()\n",
        "        z = z.to(\"cpu\").detach().numpy()\n",
        "        cp = cp.to(\"cpu\").detach().numpy()\n",
        "        # solve\n",
        "        for i in range(cp.shape[0]):\n",
        "            # sol for pred cost\n",
        "            optmodel.setObj(cp[i])\n",
        "            wpi, _ = optmodel.solve()\n",
        "            # obj with true cost\n",
        "            zpi = np.dot(wpi, c[i])\n",
        "            # round\n",
        "            zpi = zpi.round(1)\n",
        "            zi = z[i,0].round(1)\n",
        "            # regret\n",
        "            regret = (zpi - zi).round(1)\n",
        "            data[\"Regret\"].append(regret)\n",
        "            data[\"Relative Regret\"].append(regret / zi)\n",
        "            # accuracy\n",
        "            data[\"Accuracy\"].append((abs(wpi - w[i]) < 0.5).mean())\n",
        "            # optimal\n",
        "            data[\"Optimal\"].append(abs(regret) < 1e-5)\n",
        "    # dataframe\n",
        "    df = pd.DataFrame.from_dict(data)\n",
        "    # print\n",
        "    time.sleep(1)\n",
        "    print(\"Avg Regret: {:.4f}\".format(df[\"Regret\"].mean()))\n",
        "    print(\"Avg Rel Regret: {:.2f}%\".format(df[\"Relative Regret\"].mean()*100))\n",
        "    print(\"Path Accuracy: {:.2f}%\".format(df[\"Accuracy\"].mean()*100))\n",
        "    print(\"Optimality Ratio: {:.2f}%\".format(df[\"Optimal\"].mean()*100))\n",
        "    return df"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "id": "bd4d46e5",
      "metadata": {},
      "outputs": [],
      "source": [
        "def accuracy(predmodel, optmodel, dataloader):\n",
        "    \"\"\"\n",
        "    A function to evaluate model performance with accuracy.\n",
        "    Writtne by Daniel McKenzie in the style of PyEPO.\n",
        "\n",
        "    Args:\n",
        "        predmodel (nn): a regression neural network for cost prediction\n",
        "        optmodel (optModel): an PyEPO optimization model\n",
        "        dataloader (DataLoader): Torch dataloader from optDataSet\n",
        "\n",
        "    Returns:\n",
        "        float: true regret loss\n",
        "    \"\"\"\n",
        "    # evaluate\n",
        "    predmodel.eval()\n",
        "    loss = 0\n",
        "    optsum = 0\n",
        "    # load data\n",
        "    for data in dataloader:\n",
        "        x, c, w, z = data\n",
        "        batch_loss = 0\n",
        "        # cuda\n",
        "        if next(predmodel.parameters()).is_cuda:\n",
        "            x, c, w, z = x.cuda(), c.cuda(), w.cuda(), z.cuda()\n",
        "        # predict\n",
        "        with torch.no_grad(): # no grad\n",
        "            cp = predmodel(x).to(\"cpu\").detach().numpy()\n",
        "        # solve\n",
        "        for j in range(cp.shape[0]):\n",
        "            # accumulate loss\n",
        "            batch_loss += calAccuracy(optmodel, cp[j], w[j].to(\"cpu\").detach().numpy(),j)\n",
        "        loss += batch_loss/cp.shape[0]\n",
        "    # turn back train mode\n",
        "    predmodel.train()\n",
        "    # normalized\n",
        "    return loss # divide by batch size\n",
        "\n",
        "\n",
        "def calAccuracy(optmodel, pred_cost, true_sol,idx):\n",
        "    \"\"\"\n",
        "    A function to calculate normalized true regret for a batch\n",
        "\n",
        "    Args:\n",
        "        optmodel (optModel): optimization model\n",
        "        pred_cost (torch.tensor): predicted costs\n",
        "        true_sol (torch.tensor): true solution\n",
        "\n",
        "    Returns:\n",
        "        acc: 1 if true_sol matches that computed using pred_cost to within a small tolerance.\n",
        "        \n",
        "    \"\"\"\n",
        "    # opt sol for pred cost\n",
        "    optmodel.setObj(pred_cost)\n",
        "    sol, _ = optmodel.solve()\n",
        "    if np.linalg.norm(sol - true_sol)< 1e-4:\n",
        "        acc = 1\n",
        "    else:\n",
        "        acc = 0\n",
        "    return acc"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 16,
      "id": "8ca5993d",
      "metadata": {
        "id": "8ca5993d"
      },
      "outputs": [],
      "source": [
        "def plotLearningCurve(loss_log, regret_log, epochs):\n",
        "    # draw loss during training\n",
        "    plt.figure(figsize=(8, 4))\n",
        "    plt.plot(loss_log, color=\"c\")\n",
        "    plt.xticks(fontsize=10)\n",
        "    plt.yticks(fontsize=10)\n",
        "    plt.xlim(-100, len(loss_log)+100)\n",
        "    plt.xlabel(\"Iters\", fontsize=12)\n",
        "    plt.ylabel(\"Loss\", fontsize=12)\n",
        "    plt.title(\"Learning Curve on Training Set\", fontsize=12)\n",
        "    plt.show()\n",
        "    # draw normalized regret on test\n",
        "    plt.figure(figsize=(8, 4))\n",
        "    plt.plot([i*log_step for i in range(len(regret_log))], regret_log, color=\"royalblue\")\n",
        "    plt.xticks(fontsize=10)\n",
        "    plt.yticks(fontsize=10)\n",
        "    plt.xlim(-epochs/50, epochs+epochs/50)\n",
        "    plt.ylim(0, max(regret_log[1:])*1.1)\n",
        "    plt.xlabel(\"Epochs\", fontsize=12)\n",
        "    plt.ylabel(\"Normalized Regret\", fontsize=12)\n",
        "    plt.title(\"Learning Curve on Test Set\", fontsize=12)\n",
        "    plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "871b6c66",
      "metadata": {
        "id": "871b6c66"
      },
      "source": [
        "## 6 Training"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a290a155",
      "metadata": {
        "id": "a290a155"
      },
      "source": [
        "### 6.1 Baseline\n",
        "Baseline model: training with binary cross entropy loss of solutions"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 24,
      "id": "9609a0a3",
      "metadata": {
        "id": "9609a0a3"
      },
      "outputs": [],
      "source": [
        "# init net\n",
        "nnet = partialResNet(k=12)\n",
        "# cuda\n",
        "if torch.cuda.is_available():\n",
        "    nnet = nnet.cuda()\n",
        "# set optimizer\n",
        "optimizer = torch.optim.Adam(nnet.parameters(), lr=lr)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 25,
      "id": "e33f9bc6",
      "metadata": {
        "id": "e33f9bc6"
      },
      "outputs": [],
      "source": [
        "# set loss\n",
        "bceloss = nn.BCELoss()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 28,
      "id": "027f0153",
      "metadata": {
        "id": "027f0153",
        "outputId": "e35b1327-3d46-4f88-d98e-3602936a25d5"
      },
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "Epoch: 149, Loss: 0.2561: 100%|██████████| 150/150 [04:11<00:00,  1.68s/it]\n"
          ]
        }
      ],
      "source": [
        "# train\n",
        "loss_log_baseline = []\n",
        "regret_log_baseline = []\n",
        "acc_log_baseline = []\n",
        "epoch_time_log_baseline = []\n",
        "train_time_baseline = 0\n",
        "nnet.train()\n",
        "tbar = tqdm(range(150))\n",
        "for epoch in tbar:\n",
        "    start_time_epoch = time.time()\n",
        "    for x, c, w, z in loader_train:\n",
        "        # cuda\n",
        "        if torch.cuda.is_available():\n",
        "            x, c, w, z = x.cuda(), c.cuda(), w.cuda(), z.cuda()\n",
        "        # forward pass\n",
        "        h = nnet(x)\n",
        "        wp = torch.sigmoid(h)\n",
        "        loss = bceloss(wp, w) # loss\n",
        "        # backward pass\n",
        "        optimizer.zero_grad()\n",
        "        loss.backward()\n",
        "        optimizer.step()\n",
        "        # log\n",
        "        loss_log_baseline.append(loss.item())\n",
        "        tbar.set_description(\"Epoch: {:2}, Loss: {:3.4f}\".format(epoch, loss.item()))\n",
        "    \n",
        "    end_time_epoch = time.time()\n",
        "    epoch_time = end_time_epoch - start_time_epoch\n",
        "    train_time_baseline += epoch_time\n",
        "    epoch_time_log_baseline.append(epoch_time)\n",
        "    # scheduled learning rate\n",
        "    if (epoch == 90) or (epoch == 120):\n",
        "        for g in optimizer.param_groups:\n",
        "            g['lr'] /= 10"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 30,
      "id": "eef45f54",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Test set:\n"
          ]
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "100%|██████████| 15/15 [00:19<00:00,  1.30s/it]\n"
          ]
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Avg Regret: 487.8343\n",
            "Avg Rel Regret: 1911.50%\n",
            "Path Accuracy: 10.56%\n",
            "Optimality Ratio: 0.00%\n",
            "True test accuracy is 0.0\n"
          ]
        }
      ],
      "source": [
        "# Evaluate\n",
        "print(\"Test set:\")\n",
        "df_baseline = evaluate(nnet, optmodel, loader_test)\n",
        "test_acc = accuracy(nnet, optmodel, loader_test)\n",
        "print(f'True test accuracy is {test_acc}')"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 31,
      "id": "a04beb0c",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "251.65759181976318\n"
          ]
        }
      ],
      "source": [
        "print(train_time_baseline)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "dd15a583",
      "metadata": {
        "id": "dd15a583"
      },
      "source": [
        "### 6.4 DBB"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "509eb432",
      "metadata": {
        "id": "509eb432"
      },
      "source": [
        "DBB model: training with differentiable black-box optimizer and MSE of solutions"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 17,
      "id": "00de53b7",
      "metadata": {
        "id": "00de53b7"
      },
      "outputs": [],
      "source": [
        "# init net\n",
        "nnet = partialResNet(k=12)\n",
        "# cuda\n",
        "if torch.cuda.is_available():\n",
        "    nnet = nnet.cuda()\n",
        "# set optimizer\n",
        "optimizer = torch.optim.Adam(nnet.parameters(), lr=1e-5)\n",
        "# set stopper\n",
        "#stopper = earlyStopper(patience=7)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 20,
      "id": "6f982a1f",
      "metadata": {
        "id": "6f982a1f",
        "outputId": "9bd35b56-0d7d-47c5-c636-acdbb4fa0b41"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Num of cores: 1\n"
          ]
        }
      ],
      "source": [
        "# init dbb\n",
        "dbb = pyepo.func.blackboxOpt(optmodel, lambd=10, processes=1)\n",
        "# set loss\n",
        "class hammingLoss(torch.nn.Module):\n",
        "    def forward(self, wp, w):\n",
        "        loss = wp * (1.0 - w) + (1.0 - wp) * w\n",
        "        return loss.mean(dim=0).sum()\n",
        "hmloss = hammingLoss()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 21,
      "id": "071cf53e",
      "metadata": {
        "id": "071cf53e",
        "outputId": "0d2e5d23-c89b-4949-e52e-ac3b8b1b8542"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "regret is 0.7751119041482185\n"
          ]
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "Epoch:  0, Loss: 16.6667:   2%|▏         | 1/50 [06:41<5:27:50, 401.45s/it]"
          ]
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "regret is 0.5111030454320749\n"
          ]
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "Epoch:  1, Loss: 17.4500:   4%|▍         | 2/50 [13:23<5:21:21, 401.69s/it]"
          ]
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "regret is 0.5552937460931218\n"
          ]
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "Epoch:  2, Loss: 18.0500:   6%|▌         | 3/50 [20:03<5:14:10, 401.07s/it]"
          ]
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "regret is 0.5342175768519373\n"
          ]
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "Epoch:  3, Loss: 18.1143:   6%|▌         | 3/50 [21:10<5:31:45, 423.53s/it]\n"
          ]
        },
        {
          "ename": "KeyboardInterrupt",
          "evalue": "",
          "output_type": "error",
          "traceback": [
            "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
            "\u001b[0;31mKeyboardInterrupt\u001b[0m                         Traceback (most recent call last)",
            "Cell \u001b[0;32mIn[21], line 19\u001b[0m\n\u001b[1;32m     17\u001b[0m \u001b[38;5;66;03m# forward pass\u001b[39;00m\n\u001b[1;32m     18\u001b[0m cp \u001b[38;5;241m=\u001b[39m nnet(x) \u001b[38;5;66;03m# predicted cost\u001b[39;00m\n\u001b[0;32m---> 19\u001b[0m wp \u001b[38;5;241m=\u001b[39m \u001b[43mdbb\u001b[49m\u001b[43m(\u001b[49m\u001b[43mcp\u001b[49m\u001b[43m)\u001b[49m \u001b[38;5;66;03m# black-box optimizer\u001b[39;00m\n\u001b[1;32m     20\u001b[0m loss \u001b[38;5;241m=\u001b[39m hmloss(wp, w) \u001b[38;5;66;03m# loss\u001b[39;00m\n\u001b[1;32m     21\u001b[0m \u001b[38;5;66;03m# backward pass\u001b[39;00m\n",
            "File \u001b[0;32m~/Research/Implicit-Networks/Environments/fpo-dys-env/lib/python3.8/site-packages/torch/nn/modules/module.py:1501\u001b[0m, in \u001b[0;36mModule._call_impl\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m   1496\u001b[0m \u001b[38;5;66;03m# If we don't have any hooks, we want to skip the rest of the logic in\u001b[39;00m\n\u001b[1;32m   1497\u001b[0m \u001b[38;5;66;03m# this function, and just call forward.\u001b[39;00m\n\u001b[1;32m   1498\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m (\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_backward_hooks \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_backward_pre_hooks \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_forward_hooks \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_forward_pre_hooks\n\u001b[1;32m   1499\u001b[0m         \u001b[38;5;129;01mor\u001b[39;00m _global_backward_pre_hooks \u001b[38;5;129;01mor\u001b[39;00m _global_backward_hooks\n\u001b[1;32m   1500\u001b[0m         \u001b[38;5;129;01mor\u001b[39;00m _global_forward_hooks \u001b[38;5;129;01mor\u001b[39;00m _global_forward_pre_hooks):\n\u001b[0;32m-> 1501\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mforward_call\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m   1502\u001b[0m \u001b[38;5;66;03m# Do not call functions when jit is used\u001b[39;00m\n\u001b[1;32m   1503\u001b[0m full_backward_hooks, non_full_backward_hooks \u001b[38;5;241m=\u001b[39m [], []\n",
            "File \u001b[0;32m~/Research/Implicit-Networks/Environments/fpo-dys-env/lib/python3.8/site-packages/pyepo/func/blackbox.py:53\u001b[0m, in \u001b[0;36mblackboxOpt.forward\u001b[0;34m(self, pred_cost)\u001b[0m\n\u001b[1;32m     49\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mforward\u001b[39m(\u001b[38;5;28mself\u001b[39m, pred_cost):\n\u001b[1;32m     50\u001b[0m \u001b[38;5;250m    \u001b[39m\u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m     51\u001b[0m \u001b[38;5;124;03m    Forward pass\u001b[39;00m\n\u001b[1;32m     52\u001b[0m \u001b[38;5;124;03m    \"\"\"\u001b[39;00m\n\u001b[0;32m---> 53\u001b[0m     sols \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdbb\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mapply\u001b[49m\u001b[43m(\u001b[49m\u001b[43mpred_cost\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mlambd\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43moptmodel\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m     54\u001b[0m \u001b[43m                          \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mprocesses\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mpool\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msolve_ratio\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[1;32m     55\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m sols\n",
            "File \u001b[0;32m~/Research/Implicit-Networks/Environments/fpo-dys-env/lib/python3.8/site-packages/torch/autograd/function.py:506\u001b[0m, in \u001b[0;36mFunction.apply\u001b[0;34m(cls, *args, **kwargs)\u001b[0m\n\u001b[1;32m    503\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m torch\u001b[38;5;241m.\u001b[39m_C\u001b[38;5;241m.\u001b[39m_are_functorch_transforms_active():\n\u001b[1;32m    504\u001b[0m     \u001b[38;5;66;03m# See NOTE: [functorch vjp and autograd interaction]\u001b[39;00m\n\u001b[1;32m    505\u001b[0m     args \u001b[38;5;241m=\u001b[39m _functorch\u001b[38;5;241m.\u001b[39mutils\u001b[38;5;241m.\u001b[39munwrap_dead_wrappers(args)\n\u001b[0;32m--> 506\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43msuper\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mapply\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m  \u001b[38;5;66;03m# type: ignore[misc]\u001b[39;00m\n\u001b[1;32m    508\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mcls\u001b[39m\u001b[38;5;241m.\u001b[39msetup_context \u001b[38;5;241m==\u001b[39m _SingleLevelFunction\u001b[38;5;241m.\u001b[39msetup_context:\n\u001b[1;32m    509\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mRuntimeError\u001b[39;00m(\n\u001b[1;32m    510\u001b[0m         \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mIn order to use an autograd.Function with functorch transforms \u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m    511\u001b[0m         \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m(vmap, grad, jvp, jacrev, ...), it must override the setup_context \u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m    512\u001b[0m         \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mstaticmethod. For more details, please see \u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m    513\u001b[0m         \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mhttps://pytorch.org/docs/master/notes/extending.func.html\u001b[39m\u001b[38;5;124m'\u001b[39m)\n",
            "File \u001b[0;32m~/Research/Implicit-Networks/Environments/fpo-dys-env/lib/python3.8/site-packages/pyepo/func/blackbox.py:87\u001b[0m, in \u001b[0;36mblackboxOptFunc.forward\u001b[0;34m(ctx, pred_cost, lambd, optmodel, processes, pool, solve_ratio, module)\u001b[0m\n\u001b[1;32m     85\u001b[0m rand_sigma \u001b[38;5;241m=\u001b[39m np\u001b[38;5;241m.\u001b[39mrandom\u001b[38;5;241m.\u001b[39muniform()\n\u001b[1;32m     86\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m rand_sigma \u001b[38;5;241m<\u001b[39m\u001b[38;5;241m=\u001b[39m solve_ratio:\n\u001b[0;32m---> 87\u001b[0m     sol, _ \u001b[38;5;241m=\u001b[39m \u001b[43m_solve_in_pass\u001b[49m\u001b[43m(\u001b[49m\u001b[43mcp\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43moptmodel\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mprocesses\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mpool\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m     88\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m solve_ratio \u001b[38;5;241m<\u001b[39m \u001b[38;5;241m1\u001b[39m:\n\u001b[1;32m     89\u001b[0m         \u001b[38;5;66;03m# add into solpool\u001b[39;00m\n\u001b[1;32m     90\u001b[0m         module\u001b[38;5;241m.\u001b[39msolpool \u001b[38;5;241m=\u001b[39m np\u001b[38;5;241m.\u001b[39mconcatenate((module\u001b[38;5;241m.\u001b[39msolpool, sol))\n",
            "File \u001b[0;32m~/Research/Implicit-Networks/Environments/fpo-dys-env/lib/python3.8/site-packages/pyepo/func/utlis.py:25\u001b[0m, in \u001b[0;36m_solve_in_pass\u001b[0;34m(cp, optmodel, processes, pool)\u001b[0m\n\u001b[1;32m     22\u001b[0m obj \u001b[38;5;241m=\u001b[39m []\n\u001b[1;32m     23\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m i \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mrange\u001b[39m(ins_num):\n\u001b[1;32m     24\u001b[0m     \u001b[38;5;66;03m# solve\u001b[39;00m\n\u001b[0;32m---> 25\u001b[0m     \u001b[43moptmodel\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msetObj\u001b[49m\u001b[43m(\u001b[49m\u001b[43mcp\u001b[49m\u001b[43m[\u001b[49m\u001b[43mi\u001b[49m\u001b[43m]\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m     26\u001b[0m     solp, objp \u001b[38;5;241m=\u001b[39m optmodel\u001b[38;5;241m.\u001b[39msolve()\n\u001b[1;32m     27\u001b[0m     sol\u001b[38;5;241m.\u001b[39mappend(solp)\n",
            "Cell \u001b[0;32mIn[12], line 131\u001b[0m, in \u001b[0;36mshortestPathModel.setObj\u001b[0;34m(self, c)\u001b[0m\n\u001b[1;32m    129\u001b[0m c \u001b[38;5;241m=\u001b[39m c\u001b[38;5;241m.\u001b[39mreshape(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mgrid)\n\u001b[1;32m    130\u001b[0m \u001b[38;5;66;03m# sum up vector cost\u001b[39;00m\n\u001b[0;32m--> 131\u001b[0m obj \u001b[38;5;241m=\u001b[39m c[\u001b[38;5;241m0\u001b[39m,\u001b[38;5;241m0\u001b[39m] \u001b[38;5;241m+\u001b[39m \u001b[43mgp\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mquicksum\u001b[49m\u001b[43m(\u001b[49m\u001b[43mc\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mnodes_map\u001b[49m\u001b[43m[\u001b[49m\u001b[43mj\u001b[49m\u001b[43m]\u001b[49m\u001b[43m]\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mx\u001b[49m\u001b[43m[\u001b[49m\u001b[43mi\u001b[49m\u001b[43m,\u001b[49m\u001b[43mj\u001b[49m\u001b[43m]\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mfor\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mi\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mj\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01min\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mx\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    132\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_model\u001b[38;5;241m.\u001b[39msetObjective(obj)\n",
            "File \u001b[0;32msrc/gurobipy/gurobi.pxi:3706\u001b[0m, in \u001b[0;36mgurobipy.quicksum\u001b[0;34m()\u001b[0m\n",
            "Cell \u001b[0;32mIn[12], line 131\u001b[0m, in \u001b[0;36m<genexpr>\u001b[0;34m(.0)\u001b[0m\n\u001b[1;32m    129\u001b[0m c \u001b[38;5;241m=\u001b[39m c\u001b[38;5;241m.\u001b[39mreshape(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mgrid)\n\u001b[1;32m    130\u001b[0m \u001b[38;5;66;03m# sum up vector cost\u001b[39;00m\n\u001b[0;32m--> 131\u001b[0m obj \u001b[38;5;241m=\u001b[39m c[\u001b[38;5;241m0\u001b[39m,\u001b[38;5;241m0\u001b[39m] \u001b[38;5;241m+\u001b[39m gp\u001b[38;5;241m.\u001b[39mquicksum(\u001b[43mc\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mnodes_map\u001b[49m\u001b[43m[\u001b[49m\u001b[43mj\u001b[49m\u001b[43m]\u001b[49m\u001b[43m]\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mx\u001b[49m\u001b[43m[\u001b[49m\u001b[43mi\u001b[49m\u001b[43m,\u001b[49m\u001b[43mj\u001b[49m\u001b[43m]\u001b[49m \u001b[38;5;28;01mfor\u001b[39;00m i, j \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mx)\n\u001b[1;32m    132\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_model\u001b[38;5;241m.\u001b[39msetObjective(obj)\n",
            "\u001b[0;31mKeyboardInterrupt\u001b[0m: "
          ]
        }
      ],
      "source": [
        "# train\n",
        "regret = pyepo.metric.regret(nnet, optmodel, loader_test)\n",
        "loss_log_dbb = []\n",
        "regret_log_dbb = [regret]\n",
        "acc_log_dbb = []\n",
        "epoch_time_log_dbb = []\n",
        "train_time_dbb = 0\n",
        "print(f'regret is {regret}')\n",
        "tbar = tqdm(range(epochs))\n",
        "for epoch in tbar:\n",
        "    nnet.train()\n",
        "    start_time_epoch = time.time()\n",
        "    for x, c, w, z in loader_train:\n",
        "        # cuda\n",
        "        if torch.cuda.is_available():\n",
        "            x, c, w, z = x.cuda(), c.cuda(), w.cuda(), z.cuda()\n",
        "        # forward pass\n",
        "        cp = nnet(x) # predicted cost\n",
        "        wp = dbb(cp) # black-box optimizer\n",
        "        loss = hmloss(wp, w) # loss\n",
        "        # backward pass\n",
        "        optimizer.zero_grad()\n",
        "        loss.backward()\n",
        "        optimizer.step()\n",
        "        # log\n",
        "        loss_log_dbb.append(loss.item())\n",
        "        epoch_time = start_time_epoch - time.time()\n",
        "        train_time_dbb += epoch_time\n",
        "        epoch_time_log_dbb.append(epoch_time)\n",
        "\n",
        "        tbar.set_description(\"Epoch: {:2}, Loss: {:3.4f}\".format(epoch, loss.item()))\n",
        "    # scheduled learning rate\n",
        "    if (epoch == int(epochs*0.6)) or (epoch == int(epochs*0.8)):\n",
        "        for g in optimizer.param_groups:\n",
        "            g['lr'] /= 10\n",
        "    if epoch % log_step == 0:\n",
        "        # log regret\n",
        "        regret = pyepo.metric.regret(nnet, optmodel, loader_test) # regret on test\n",
        "        regret_log_dbb.append(regret)\n",
        "        print(f'regret is {regret}')\n",
        "        # early stop\n",
        "        #regret = pyepo.metric.regret(nnet, optmodel, loader_val) # regret on val\n",
        "        #if stopper.stop(regret):\n",
        "        #    break"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "a6dbba91",
      "metadata": {
        "id": "a6dbba91",
        "outputId": "d9398d54-5d2c-4439-a0f5-7dccd0aa78fd"
      },
      "outputs": [
        {
          "data": {
            "image/png": "iVBORw0KGgoAAAANSUhEUgAAAr4AAAGNCAYAAAD3gXLrAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8pXeV/AAAACXBIWXMAAA9hAAAPYQGoP6dpAABufUlEQVR4nO3dd3hUZd4+8Ht66kwS0ggkEEBCFREBEaUIElhEKe+ufcGKLqjoyiryrqK+il3XFcv+VFgriIq4uuKiUhakSFUEQwsEgSSQNunTnt8fOedwZjKTzKTOZO7PdeWSnDlz5pljCHe++T7PoxFCCBARERERdXDa9h4AEREREVFbYPAlIiIiorDA4EtEREREYYHBl4iIiIjCAoMvEREREYUFBl8iIiIiCgsMvkREREQUFhh8iYiIiCgsMPgSERERUVhg8CWioNC9e3fMmjWrvYdBQejYsWPQaDRYtmxZk56v0WiwaNGiFh0TEYUmBl+iDmTZsmXQaDTYsWNHew8l5NTU1OCll17C8OHDYbFYEBERgd69e2Pu3Lk4ePBgew8vKC1atAgajabRjzFjxrT3UNvNmTNncO+996JPnz6IjIxEcnIyhg0bhgcffBAVFRUBX++HH37AokWLUFpa2vKDJQoD+vYeABERAOTk5ECrbZ+fxc+ePYuJEydi586duPLKK3H99dcjJiYGOTk5WL58Of7xj3/AZrO1y9iC2fTp09GrVy/l84qKCtx1112YNm0apk+frhxPSUlp1ut069YN1dXVMBgMTXp+dXU19Pq2/+euuLgYF110EaxWK2655Rb06dMHRUVF+Omnn/D666/jrrvuQkxMTEDX/OGHH/DYY49h1qxZiIuLa52BE3VgDL5E1OIcDgdcLheMRqPfzzGZTK04oobNmjULu3fvxieffIIZM2a4PfbEE09g4cKFLfI6Tbkvwez888/H+eefr3x+9uxZ3HXXXTj//PNx4403+nxeTU0NjEaj3z/oaDQaRERENHmczXluc7z99tvIy8vD5s2bcckll7g9ZrVaO8zXAVEoYasDURg6efIkbrnlFqSkpMBkMqF///5455133M6x2Wx45JFHMGTIEFgsFkRHR+Oyyy7DunXr3M6T+y+ff/55vPzyy+jZsydMJhP279+v/Cr88OHDSoXKYrHg5ptvRlVVldt1PHt85baNzZs34/7770dS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OHToEH766SefP1Co/195ku9LVlaW23Gj0YgePXooj8u6du3q9gMGUHevf/rppwbenf+83QeXy4W//e1veO2115Cbm+vWm9upU6dGrxkREVHv3sTHxytfG41p7Ovy+PHj0Gq19cbu+bXWkM6dO+P111/Ha6+9hkOHDuGbb77BM888g0ceeQSdO3fGbbfdhkOHDgFAg+0QZWVlfn09E1HDGHyJwohcNbrxxht9/iMrz9J///33MWvWLEydOhXz589HcnIydDodFi9ejCNHjtR7nmc1T02n03k9Lle8GtKc5/qjT58+AICff/4Zl112WaPnazQar6/tOaFK5uu+XHvttbj55puxZ88eXHDBBfj4448xbtw4pW8TqPv/dcUVV+Avf/mL12v07t270fH6q7Xvs7f78NRTT+Gvf/0rbrnlFjzxxBNISEiAVqvFvHnz/Kpw+hqzv1r7PatpNBr07t0bvXv3xuTJk3Heeefhgw8+wG233aa81+eee65e77ws0GXPiMg7Bl+iMJKUlITY2Fg4nU6MHz++wXM/+eQT9OjRA5999plbJdBzQlZ769atGwDg8OHDbpW5oqIivyp/U6ZMweLFi/H+++/7FXzj4+O9/irds4LamKlTp2L27NlKu8PBgwexYMECt3N69uyJioqKRv9feSPfl5ycHPTo0UM5brPZkJub26RrtrRPPvkEY8eOxdtvv+12vLS01O0HgPbSrVs3uFwu5Obm4rzzzlOOHz58uFnX7dGjB+Lj43H69GkAdf+fgbrfPjT2/8WzKk9EgWGPL1EY0el0mDFjBj799FPs27ev3uPqZcLkapi6+rVt2zZs2bKl9QcagHHjxkGv1+P11193O65eEqwhI0aMwMSJE/HWW2/h888/r/e4zWbDAw88oHzes2dP/Prrr273au/evW7LTvkjLi4O2dnZ+Pjjj7F8+XIYjUZMnTrV7Zw//OEP2LJlC7755pt6zy8tLYXD4fB5/fHjx8NoNOKVV15x+3/49ttvo6yszO+VCVqTTqerV11duXIlTp482U4jcpednQ2gbkk4tb///e9+PX/btm2orKysd3z79u0oKipS2lCGDBmCnj174vnnn/e6m5v6ay06OhoAuHMbUROx4kvUAb3zzjvKxBy1e++9F08//TTWrVuH4cOH4/bbb0e/fv1QXFyMXbt24dtvv0VxcTEA4Morr8Rnn32GadOmYfLkycjNzcUbb7yBfv36NWmr1daSkpKCe++9Fy+88AKuuuoqTJw4EXv37sXXX3+NxMREvypk7777LiZMmIDp06djypQpGDduHKKjo3Ho0CEsX74cp0+fVtbyveWWW/Diiy8iOzsbt956KwoLC/HGG2+gf//+fk3WU7vmmmtw44034rXXXkN2dna9HuP58+fjiy++wJVXXolZs2ZhyJAhqKysxM8//4xPPvkEx44d81kZTUpKwoIFC/DYY49h4sSJuOqqq5CTk4PXXnsNQ4cObXCDibZy5ZVX4vHHH8fNN9+MSy65BD///DM++OADtwp1exoyZAhmzJiBl19+GUVFRcpyZvIW1o19bb333nv44IMPMG3aNAwZMgRGoxEHDhzAO++8g4iICDz88MMAAK1Wi7feeguTJk1C//79cfPNN6NLly44efIk1q1bB7PZjH/961/KmABg4cKFuPbaa2EwGDBlyhQlEBNRwxh8iTogz+qnbNasWejatSu2b9+Oxx9/HJ999hlee+01dOrUCf3796+3fml+fj7efPNNfPPNN+jXrx/ef/99rFy5EuvXr2+jd+KfZ555BlFRUfh//+//4dtvv8WIESPwn//8B5deeqlfu3YlJSXhhx9+wGuvvYYVK1Zg4cKFsNls6NatG6666irce++9yrl9+/bFu+++i0ceeQT3338/+vXrh/feew8ffvhhwPflqquuQmRkJMrLy91Wc5BFRUVhw4YNeOqpp7By5Uq8++67MJvN6N27Nx577DFYLJYGr79o0SIkJSXh1VdfxX333YeEhATccccdeOqpp5q8/W9Levjhh1FZWYkPP/wQK1aswIUXXoivvvoKDz30UHsPTfHuu+8iNTUVH330EVatWoXx48djxYoVyMrKavRra/bs2YiKisJ3332H1atXw2q1IikpCRMmTMCCBQswePBg5dwxY8Zgy5YteOKJJ/Dqq6+ioqICqampGD58OGbPnq2cN3ToUDzxxBN44403sGbNGqUVg8GXyD8a0Rpd/ERE7ay0tBTx8fH4v//7vxbbcpgIqFt+bPDgwXj//fdxww03tPdwiCgA7PElopBXXV1d75i8q5m37YWJ/OXra0ur1WLUqFHtMCIiag62OhBRyFuxYgWWLVuG3/3ud4iJicGmTZvw0UcfYcKECRg5cmR7D49C2LPPPoud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Wur+dtjgO3PmTAGg3se6deuUc44dOyYmTZokIiMjRWJiovjzn/8s7Ha723XWrVsnLrjgAmE0GkWPHj3E0qVL2/aNhIidO3eK4cOHC4vFIiIiIkTfvn3FU0895fZNVwgh9u7dKy699FJhMplEly5dxNNPP91OIw5Nf//730VGRoYwGo1i2LBhYuvWre09pJB0zTXXiM6dOwuj0Si6dOkirrnmGnH48GHl8erqavGnP/1JxMfHi6ioKDFt2jRx+vTpdhxx8Fu3bp3X77kzZ84UQtQtafbXv/5VpKSkCJPJJMaNGydycnLcrlFUVCSuu+46ERMTI8xms7j55puVYkW4a+j+VlVViQkTJoikpCRhMBhEt27dxO23317vh2LeX9+83VsAbv/m+/N9wZ9cEY4au795eXli1KhRIiEhQZhMJtGrVy8xf/58UVZW5nadlri/GmlAREREREQdWkj1+BIRERERNRWDLxERERGFBQZfIiIiIgoLDL5EREREFBYYfImIiIgoLDD4EhEREVFYYPAlIiIiorDA4EtEREREYYHBl4iIiIjCAoMvEVE7W7ZsGTQaDXbs2AEA+Pe//41Fixa176CIiDogBl8ioiDz73//G4899lh7D4OIqMNh8CUiCgNCCFRXV7f3MIiI2hWDLxFREJk1axaWLFkCANBoNMqHzOVy4eWXX0b//v0RERGBlJQUzJ49GyUlJW7X6d69O6688kp88803uOiiixAZGYk333wTALB27VpceumliIuLQ0xMDLKysvDwww+33ZskImon+vYeABERnTN79mycOnUKa9euxXvvvef18WXLluHmm2/GPffcg9zcXLz66qvYvXs3Nm/eDIPBoJybk5OD6667DrNnz8btt9+OrKws/PLLL7jyyitx/vnn4/HHH4fJZMLhw4exefPmtnybRETtgsGXiCiIjBgxAr1798batWtx4403uj22adMmvPXWW/jggw9w/fXXK8fHjh2LiRMnYuXKlW7HDx8+jDVr1iA7O1s59vLLL8Nms+Hrr79GYmJi678hIqIgwlYHIqIQsXLlSlgsFlxxxRU4e/as8jFkyBDExMRg3bp1budnZma6hV4AiIuLAwCsXr0aLperrYZORBQUGHyJiELEoUOHUFZWhuTkZCQlJbl9VFRUoLCw0O38zMzMete45pprMHLkSNx2221ISUnBtddei48//pghmIjCAlsdiIhChMvlQnJyMj744AOvjyclJbl9HhkZWe+cyMhIbNy4EevWrcNXX32FNWvWYMWKFbj88svxn//8BzqdrlXGTkQUDBh8iYiCjHoVB7WePXvi22+/xciRI72GWn9ptVqMGzcO48aNw4svvoinnnoKCxcuxLp16zB+/PgmX5eIKNix1YGIKMhER0cDAEpLS92O/+EPf4DT6cQTTzxR7zkOh6Pe+d4UFxfXO3bBBRcAAGprawMeKxFRKGHFl4goyAwZMgQAcM899yA7Oxs6nQ7XXnstRo8ejdmzZ2Px4sXYs2cPJkyYAIPBgEOHDmHlypX429/+hv/5n/9p8NqPP/44Nm7ciMmTJ6Nbt24oLCzEa6+9hq5du+LSSy9ti7dHRNRuGHyJiILM9OnTcffdd2P58uV4//33IYTAtddeCwB44403MGTIELz55pt4+OGHodfr0b17d9x4440YOXJko9e+6qqrcOzYMbzzzjs4e/YsEhMTMXr0aDz22GOwWCyt/daIiNqVRggh2nsQREREREStjT2+RERERBQWGHyJiIiIKCww+BIRERFRWGDwJSIiIqKwwOBLRERERGGBwZeIiIiIwgKDLxERERGFBQZfIiIiIgoLDL5EREREFBYYfImIiIgoLDD4EhEREVFYYPAlIiIiorDw/wGZE7TVt1P6EwAAAABJRU5ErkJggg==",
            "text/plain": [
              "<Figure size 800x400 with 1 Axes>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "image/png": "iVBORw0KGgoAAAANSUhEUgAAAtEAAAGNCAYAAADXbS0WAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8pXeV/AAAACXBIWXMAAA9hAAAPYQGoP6dpAABRUklEQVR4nO3de1xU1f7/8feAAooCIgqiCHgpNS8UykhlWHJEswtKpWZ5ybT8qSfkdJFO3spC04xMk65qp8xbZSdLS0ntW5IXSEtNjno0TQWvgGKCMvv3hw/nNIHKDGMM+Ho+HvP4MmuvvfZnzz49vu92a69tMgzDEAAAAIByc6vsAgAAAICqhhANAAAA2IkQDQAAANiJEA0AAADYiRANAAAA2IkQDQAAANiJEA0AAADYiRANAAAA2IkQDQAAANiJEA0AlxEWFqbBgwdXdhkAABdDiAZw1c2bN08mk0mbN2+u7FKqnLNnz+rVV1+V2WyWr6+vvLy8dN1112nUqFH6z3/+U9nluaSJEyfKZDJd8dO1a1enHO/LL7/UxIkTy93fYrHo/fffl9lslr+/v+rWravrrrtOAwcO1A8//GD38c+cOaOJEydq7dq1du8LwHE1KrsAAHBl2dnZcnOrnPsNx44dU48ePZSZmam77rpLDz74oOrUqaPs7GwtXLhQb731loqLiyulNlfWp08ftWjRwvr99OnTGjFihHr37q0+ffpY2wMDA51yvC+//FKzZ88ud5D++9//rtmzZ+vee+/VgAEDVKNGDWVnZ2vFihVq1qyZOnfubNfxz5w5o0mTJkmS0/7FAMCVEaIBXDPOnz8vi8UiDw+Pcu/j6el5FSu6vMGDB+vHH3/U0qVLlZCQYLPthRde0D//+U+nHMeR38WVtW/fXu3bt7d+P3bsmEaMGKH27dvroYceqsTKpNzcXL3xxhsaNmyY3nrrLZttqampOnr0aCVVBsBeTOcA4DIOHjyoRx55RIGBgfL09NQNN9yg9957z6ZPcXGxxo8fr8jISPn6+srb21tdunTRmjVrbPrt27dPJpNJ06dPV2pqqpo3by5PT0/t2LHD+p/7d+/ercGDB8vPz0++vr4aMmSIzpw5YzPOn+dEX5ya8v333yspKUkNGjSQt7e3evfuXSoAWSwWTZw4UcHBwapdu7Zuv/127dixo1zzrDds2KAvvvhCQ4cOLRWgpQvhfvr06dbvXbt2LfMu5ODBgxUWFnbF3+XHH39UjRo1rHc0/yg7O1smk0mzZs2ytuXl5SkxMVEhISHy9PRUixYtNHXqVFkslsue10VvvPGGbrjhBnl6eio4OFgjR45UXl6eTZ+uXbuqbdu22rFjh26//XbVrl1bjRs31ssvv1yuY1zJzp07dd9998nf319eXl7q2LGj/v3vf9v0OXfunCZNmqSWLVvKy8tL9evX16233qpVq1ZJuvD7zp49W5Jspopcyt69e2UYhm655ZZS20wmkxo2bGjTdqXfed++fWrQoIEkadKkSdbj2zO9BIBjuBMNwCXk5uaqc+fOMplMGjVqlBo0aKAVK1Zo6NChKigoUGJioiSpoKBA77zzjvr3769hw4bp1KlTevfddxUXF6eNGzcqIiLCZty5c+fq7NmzGj58uDw9PeXv72/d9sADDyg8PFwpKSnKysrSO++8o4YNG2rq1KlXrHf06NGqV6+eJkyYoH379ik1NVWjRo3SokWLrH2Sk5P18ssv6+6771ZcXJy2bt2quLg4nT179orjXwxzDz/8cDl+Pfv9+Xdp1KiRYmJitHjxYk2YMMGm76JFi+Tu7q77779f0oXpAzExMTp48KAee+wxNW3aVOvXr1dycrIOHz6s1NTUyx574sSJmjRpkmJjYzVixAhlZ2drzpw52rRpk77//nvVrFnT2vfkyZPq0aOH+vTpowceeEBLly7VM888o3bt2qlnz54On//27dt1yy23qHHjxho7dqy8vb21ePFixcfH6+OPP1bv3r2ttaakpOjRRx9VVFSUCgoKtHnzZmVlZelvf/ubHnvsMR06dEirVq3Sv/71ryseNzQ0VJK0ZMkS3X///apdu/Yl+5bnd27QoIHmzJlTarrKH+/EA7hKDAC4yubOnWtIMjZt2nTJPkOHDjUaNWpkHDt2zKa9X79+hq+vr3HmzBnDMAzj/PnzRlFRkU2fkydPGoGBgcYjjzxibdu7d68hyfDx8TGOHDli03/ChAmGJJv+hmEYvXv3NurXr2/TFhoaagwaNKjUucTGxhoWi8XaPmbMGMPd3d3Iy8szDMMwcnJyjBo1ahjx8fE2402cONGQZDNmWXr37m1IMk6ePHnZfhfFxMQYMTExpdoHDRpkhIaGWr9f7nd58803DUnGzz//bNPepk0b44477rB+f+GFFwxvb2/jP//5j02/sWPHGu7u7sb+/fsvWeeRI0cMDw8Po3v37kZJSYm1fdasWYYk47333rM5J0nG+++/b20rKioygoKCjISEhEse48+OHj1qSDImTJhgbevWrZvRrl074+zZs9Y2i8Vi3HzzzUbLli2tbR06dDB69ep12fFHjhxp2PP/TgcOHGhIMurVq2f07t3bmD59uvHLL7+U6lfe37ms8wNw9TGdA0ClMwxDH3/8se6++24ZhqFjx45ZP3FxccrPz1dWVpYkyd3d3Tp312Kx6MSJEzp//rw6duxo7fNHCQkJ1v/c/WePP/64zfcuXbro+PHjKigouGLNw4cPt/nP9l26dFFJSYl+/fVXSVJ6errOnz+v//f//p/NfqNHj77i2JKsNdStW7dc/e1V1u/Sp08f1ahRw+Zu+rZt27Rjxw717dvX2rZkyRJ16dJF9erVs7lWsbGxKikp0bfffnvJ465evVrFxcVKTEy0eWBz2LBh8vHx0RdffGHTv06dOjbzmD08PBQVFaX//ve/Dp/7iRMn9M033+iBBx7QqVOnrPUfP35ccXFx2rVrlw4ePChJ8vPz0/bt27Vr1y6Hj/dnc+fO1axZsxQeHq5PP/1UTz75pFq3bq1u3bpZjytV7HcGcPUxnQNApTt69Kjy8vL01ltvlXrY6qIjR45Y/54/f75eeeUV7dy5U+fOnbO2h4eHl9qvrLaLmjZtavO9Xr16ki5MIfDx8blszZfbV5I1TP9xlQhJ8vf3t/a9nIvHP3XqlPz8/K7Y315l/S4BAQHq1q2bFi9erBdeeEHShakcNWrUsFnVYteuXfrpp58u+S8nf7xWf3bxd7n++utt2j08PNSsWTPr9ouaNGlSao5xvXr19NNPP13m7C5v9+7dMgxD48aN07hx48rsc+TIETVu3FjPP/+87r33Xl133XVq27atevTooYcffrhC0yXc3Nw0cuRIjRw5UsePH9f333+vtLQ0rVixQv369dP//d//SarY7wzg6iNEA6h0Fx+SeuihhzRo0KAy+1wMLR988IEGDx6s+Ph4PfXUU2rYsKHc3d2VkpKiPXv2lNqvVq1alzyuu7t7me2GYVyx5orsWx6tWrWSJP3888/q0qXLFfubTKYyj11SUlJm/0v9Lv369dOQIUO0ZcsWRUREaPHixerWrZsCAgKsfSwWi/72t7/p6aefLnOM66677or1ltfV+J0v/u/tySefVFxcXJl9Lv7Lz2233aY9e/bos88+09dff6133nlHr776qtLS0vToo486XMNF9evX1z333KN77rlHXbt21bp16/Trr78qNDT0L/2dAdiPEA2g0jVo0EB169ZVSUmJYmNjL9t36dKlatasmT755BObO5R/fhiusl18gGz37t02d32PHz9uvVt9OXfffbdSUlL0wQcflCtE16tXr8wpDn++s3sl8fHxeuyxx6xTOv7zn/8oOTnZpk/z5s11+vTpK16rslz8XbKzs9WsWTNre3Fxsfbu3evQmPa6eNyaNWuW63j+/v4aMmSIhgwZotOnT+u2227TxIkTrSH6cqtx2KNjx45at26dDh8+rNDQ0HL/zs46PgD7MCcaQKVzd3dXQkKCPv74Y23btq3U9j8uHXfxzuQf70Ru2LBBGRkZV79QO3Tr1k01atTQnDlzbNr/uEzc5URHR6tHjx565513tGzZslLbi4uL9eSTT1q/N2/eXDt37rT5rbZu3arvv//errr9/PwUFxenxYsXa+HChfLw8FB8fLxNnwceeEAZGRn66quvSu2fl5en8+fPX3L82NhYeXh4aObMmTbX8N1331V+fr569eplV72OaNiwobp27ao333xThw8fLrX9j7/h8ePHbbbVqVNHLVq0UFFRkbXN29tbkkot0VeWnJwc7dixo1R7cXGx0tPT5ebmZr0LXt7f+eIKH+U5PgDn4U40gL/Me++9p5UrV5Zqf+KJJzRlyhStWbNGZrNZw4YNU5s2bXTixAllZWVp9erVOnHihCTprrvu0ieffKLevXurV69e2rt3r9LS0tSmTRudPn36rz6lSwoMDNQTTzyhV155Rffcc4969OihrVu3asWKFQoICCjX3cP3339f3bt3V58+fXT33XerW7du8vb21q5du7Rw4UIdPnzYulb0I488ohkzZiguLk5Dhw7VkSNHlJaWphtuuKFcD0r+Ud++ffXQQw/pjTfeUFxcXKk52U899ZT+/e9/66677tLgwYMVGRmpwsJC/fzzz1q6dKn27dtnM/3jjxo0aKDk5GRNmjRJPXr00D333KPs7Gy98cYb6tSp01/2MpTZs2fr1ltvVbt27TRs2DA1a9ZMubm5ysjI0G+//aatW7dKktq0aaOuXbsqMjJS/v7+2rx5s5YuXapRo0ZZx4qM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9pruuOMO/fzzzwoMDJQkrV69Wj179lSzZs00ceJE/f7773r99dd1yy23KCsrS2FhYZKkQ4cOKSoqSnl5eRo+fLhatWqlgwcPaunSpTpz5ow8PDysxx09erTq1aunCRMmaN++fUpNTdWoUaO0aNEiSdKRI0fUvXt3NWjQQGPHjpWfn5/27dunTz755Cr/agDgPIRoAKiCYmNjS7V5enrq7Nmz1u+7d+/Wrl271LhxY0lSjx49ZDabNXXqVM2YMUOS9NRTT8nf318ZGRny9/eXJMXHx+vGG2/UhAkTNH/+fElScnKycnJytGHDBptpJM8//7wMw7Cpo379+vr6669lMpkkSRaLRTNnzlR+fr58fX21fv16nTx5Ul9//bXNWJMnT3bGTwMAfwmmcwBAFTR79mytWrXK5rNixQqbPvHx8dYALUlRUVEym8368ssvJUmHDx/Wli1bNHjwYGuAlqT27dvrb3/7m7WfxWLRsmXLdPfdd5c5D/tiWL5o+PDhNm1dunRRSUmJfv31V0mSn5+fJGn58uU6d+5cBX4FAKg83IkGgCooKirqig8WtmzZslTbddddp8WLF0uSNdRef/31pfq1bt1aX331lQoLC3X69GkVFBSobdu25aqtadOmNt/r1asnSTp58qQkKSYmRgkJCZo0aZJeffVVde3aVfHx8XrwwQfl6elZrmMAQGXjTjQAwKnc3d3LbL847cNkMmnp0qXKyMjQqFGjdPDgQT3yyCOKjIzU6dOn/8pSAcBhhGgAqKZ27dpVqu0///mP9WHB0NBQSVJ2dnapfjt37lRAQIC8vb3VoEED+fj4lLmyR0V07txZL774ojZv3qwPP/xQ27dv18KFC516DAC4WgjRAFBNLVu2TAcPHrR+37hxozZs2KCePXtKkho1aqSIiAjNnz9feXl51n7btm3T119/rTvvvFOS5Obmpvj4eH3++edlvtL7zw8WXsnJkydL7RMRESHpwvJ4AFAVMCcaAKqgFStWaOfOnaXab775Zrm5Xbg/0qJFC916660aMWKEioqKlJqaqvr16+vpp5+29p82bZp69uyp6OhoDR061LrEna+vryZOnGjt99JLL+nrr79WTEyMhg8frtatW+vw4cNasmSJvvvuO+vDguUxf/58vfHGG+rdu7eaN2+uU6dO6e2335aPj481uAOAqyNEA0AVNH78+DLb586dq65du0qSBg4cKDc3N6WmpurIkSOKiorSrFmz1KhRI2v/2NhYrVy5UhMmTND48eNVs2ZNxcTEaOrUqTavFW/cuLE2bNigcePG6cMPP1RBQYEaN26snj17qnbt2nbVHhMTo40bN2rhwoXKzc2Vr6+voqKi9OGHH5b5KnMAcEUmw97/DgcAcGn79u1TeHi4pk2bpieffLKyywGAaok50QAAAICdCNEAAACAnQjRAAAAgJ2YEw0AAADYiTvRAAAAgJ0I0QAAAICdCNEAAACAnQjRAAAAgJ0I0QAAAICdCNEAAACAnQjRAAAAgJ0I0QAAAICd/j+0KllT3lXqPgAAAABJRU5ErkJggg==",
            "text/plain": [
              "<Figure size 800x400 with 1 Axes>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Test set:\n"
          ]
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            " 40%|████      | 6/15 [00:08<00:13,  1.48s/it]\n"
          ]
        },
        {
          "ename": "KeyboardInterrupt",
          "evalue": "",
          "output_type": "error",
          "traceback": [
            "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
            "\u001b[0;31mKeyboardInterrupt\u001b[0m                         Traceback (most recent call last)",
            "Cell \u001b[0;32mIn[33], line 5\u001b[0m\n\u001b[1;32m      3\u001b[0m \u001b[38;5;66;03m# eval\u001b[39;00m\n\u001b[1;32m      4\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mTest set:\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m----> 5\u001b[0m df4 \u001b[38;5;241m=\u001b[39m \u001b[43mevaluate\u001b[49m\u001b[43m(\u001b[49m\u001b[43mnnet\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43moptmodel\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mloader_test\u001b[49m\u001b[43m)\u001b[49m\n",
            "Cell \u001b[0;32mIn[20], line 20\u001b[0m, in \u001b[0;36mevaluate\u001b[0;34m(nnet, optmodel, dataloader)\u001b[0m\n\u001b[1;32m     17\u001b[0m \u001b[38;5;66;03m# solve\u001b[39;00m\n\u001b[1;32m     18\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m i \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mrange\u001b[39m(cp\u001b[38;5;241m.\u001b[39mshape[\u001b[38;5;241m0\u001b[39m]):\n\u001b[1;32m     19\u001b[0m     \u001b[38;5;66;03m# sol for pred cost\u001b[39;00m\n\u001b[0;32m---> 20\u001b[0m     \u001b[43moptmodel\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msetObj\u001b[49m\u001b[43m(\u001b[49m\u001b[43mcp\u001b[49m\u001b[43m[\u001b[49m\u001b[43mi\u001b[49m\u001b[43m]\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m     21\u001b[0m     wpi, _ \u001b[38;5;241m=\u001b[39m optmodel\u001b[38;5;241m.\u001b[39msolve()\n\u001b[1;32m     22\u001b[0m     \u001b[38;5;66;03m# obj with true cost\u001b[39;00m\n",
            "Cell \u001b[0;32mIn[16], line 131\u001b[0m, in \u001b[0;36mshortestPathModel.setObj\u001b[0;34m(self, c)\u001b[0m\n\u001b[1;32m    129\u001b[0m c \u001b[38;5;241m=\u001b[39m c\u001b[38;5;241m.\u001b[39mreshape(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mgrid)\n\u001b[1;32m    130\u001b[0m \u001b[38;5;66;03m# sum up vector cost\u001b[39;00m\n\u001b[0;32m--> 131\u001b[0m obj \u001b[38;5;241m=\u001b[39m c[\u001b[38;5;241m0\u001b[39m,\u001b[38;5;241m0\u001b[39m] \u001b[38;5;241m+\u001b[39m \u001b[43mgp\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mquicksum\u001b[49m\u001b[43m(\u001b[49m\u001b[43mc\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mnodes_map\u001b[49m\u001b[43m[\u001b[49m\u001b[43mj\u001b[49m\u001b[43m]\u001b[49m\u001b[43m]\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mx\u001b[49m\u001b[43m[\u001b[49m\u001b[43mi\u001b[49m\u001b[43m,\u001b[49m\u001b[43mj\u001b[49m\u001b[43m]\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mfor\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mi\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mj\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01min\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mx\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    132\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_model\u001b[38;5;241m.\u001b[39msetObjective(obj)\n",
            "File \u001b[0;32msrc/gurobipy/gurobi.pxi:3706\u001b[0m, in \u001b[0;36mgurobipy.quicksum\u001b[0;34m()\u001b[0m\n",
            "Cell \u001b[0;32mIn[16], line 131\u001b[0m, in \u001b[0;36m<genexpr>\u001b[0;34m(.0)\u001b[0m\n\u001b[1;32m    129\u001b[0m c \u001b[38;5;241m=\u001b[39m c\u001b[38;5;241m.\u001b[39mreshape(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mgrid)\n\u001b[1;32m    130\u001b[0m \u001b[38;5;66;03m# sum up vector cost\u001b[39;00m\n\u001b[0;32m--> 131\u001b[0m obj \u001b[38;5;241m=\u001b[39m c[\u001b[38;5;241m0\u001b[39m,\u001b[38;5;241m0\u001b[39m] \u001b[38;5;241m+\u001b[39m gp\u001b[38;5;241m.\u001b[39mquicksum(\u001b[43mc\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mnodes_map\u001b[49m\u001b[43m[\u001b[49m\u001b[43mj\u001b[49m\u001b[43m]\u001b[49m\u001b[43m]\u001b[49m \u001b[38;5;241m*\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mx[i,j] \u001b[38;5;28;01mfor\u001b[39;00m i, j \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mx)\n\u001b[1;32m    132\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_model\u001b[38;5;241m.\u001b[39msetObjective(obj)\n",
            "\u001b[0;31mKeyboardInterrupt\u001b[0m: "
          ]
        }
      ],
      "source": [
        "# plot\n",
        "plotLearningCurve(loss_log_dbb,  regret_log_dbb)\n",
        "# eval\n",
        "print(\"Test set:\")\n",
        "df_dbb = evaluate(nnet, optmodel, loader_test)\n",
        "test_acc = accuracy(nnet, optmodel, loader_test)\n",
        "print(f'True test accuracy is {test_acc}')\n",
        "print(f'Training time is {train_time_dbb}')\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "74fd3e7f",
      "metadata": {
        "id": "74fd3e7f"
      },
      "source": [
        "### 6.5 DPO"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5730bace",
      "metadata": {
        "id": "5730bace"
      },
      "source": [
        "DPO model: training with differentiable perturbed optimizer and MSE of solutions"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "e7688ea5",
      "metadata": {
        "id": "e7688ea5"
      },
      "outputs": [],
      "source": [
        "# init net\n",
        "nnet = partialResNet(k=12)\n",
        "# cuda\n",
        "if torch.cuda.is_available():\n",
        "    nnet = nnet.cuda()\n",
        "# set optimizer\n",
        "optimizer = torch.optim.Adam(nnet.parameters(), lr=lr)\n",
        "# set stopper\n",
        "#stopper = earlyStopper(patience=7)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "2c344cf6",
      "metadata": {
        "id": "2c344cf6",
        "outputId": "291adb81-729d-44b1-c04b-8760b3b68393"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Num of cores: 1\n"
          ]
        }
      ],
      "source": [
        "# init dpo\n",
        "ptb = pyepo.func.perturbedOpt(optmodel, n_samples=1, sigma=1.0, processes=1)\n",
        "# set loss\n",
        "mseloss = nn.MSELoss()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "ef6cfe80",
      "metadata": {
        "id": "ef6cfe80",
        "outputId": "7cb86127-d353-4b9e-e31c-1194ffeda9b8"
      },
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "Epoch: 49, Loss: 0.1216: 100%|███████████████████████████████████████████████████████████████████████| 50/50 [3:43:37<00:00, 268.35s/it]\n"
          ]
        }
      ],
      "source": [
        "# train\n",
        "loss_log5, regret_log5 = [], [pyepo.metric.regret(nnet, optmodel, loader_test)]\n",
        "tbar = tqdm(range(epochs))\n",
        "for epoch in tbar:\n",
        "    nnet.train()\n",
        "    for x, c, w, z in loader_train:\n",
        "        # cuda\n",
        "        if torch.cuda.is_available():\n",
        "            x, c, w, z = x.cuda(), c.cuda(), w.cuda(), z.cuda()\n",
        "        # forward pass\n",
        "        cp = nnet(x) # predicted cost\n",
        "        we = ptb(cp) # perturbed optimizer\n",
        "        loss = mseloss(we, w) # loss\n",
        "        # backward pass\n",
        "        optimizer.zero_grad()\n",
        "        loss.backward()\n",
        "        optimizer.step()\n",
        "        # log\n",
        "        loss_log5.append(loss.item())\n",
        "        tbar.set_description(\"Epoch: {:2}, Loss: {:3.4f}\".format(epoch, loss.item()))\n",
        "    # scheduled learning rate\n",
        "    if (epoch == int(epochs*0.6)) or (epoch == int(epochs*0.8)):\n",
        "        for g in optimizer.param_groups:\n",
        "            g['lr'] /= 10\n",
        "    if epoch % log_step == 0:\n",
        "        # log regret\n",
        "        regret = pyepo.metric.regret(nnet, optmodel, loader_test) # regret on test\n",
        "        regret_log5.append(regret)\n",
        "        # early stop\n",
        "        #regret = pyepo.metric.regret(nnet, optmodel, loader_val) # regret on val\n",
        "        #if stopper.stop(regret):\n",
        "        #    break"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "c5db27ae",
      "metadata": {
        "id": "c5db27ae",
        "outputId": "7ef1052d-1cf2-49fe-db5f-8bd2bc1e5318"
      },
      "outputs": [
        {
          "data": {
            "image/png": "iVBORw0KGgoAAAANSUhEUgAAArQAAAGICAYAAACwbnORAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8qNh9FAAAACXBIWXMAAA9hAAAPYQGoP6dpAABkp0lEQVR4nO3deVyU1f4H8M8wwLAPm2yKiLiBgAsoAiKWhde0sm43y9IsvWlmZrZ67bZYN8zS7FdhWWlZZl7TytIyurngrgi57yiog8iOCAPDnN8fwsQwMzDAwMzA5/16zevOPM95nuc7Z7j5nTPf5xyJEEKAiIiIiMhK2Zg7ACIiIiKi1mBCS0RERERWjQktEREREVk1JrREREREZNWY0BIRERGRVWNCS0RERERWjQktEREREVk1JrREREREZNWY0BIRERGRVWNCS9TBfPHFF5BIJDh48KC5Q2m2kSNHYuTIkWa7vlqtxldffYXbbrsN3t7esLOzg4+PD8aNG4effvoJarXabLFZqgsXLkAikRj1uHDhQquuNWXKFPTo0aNFx9b9/6K1MbTUvn37cM8996B79+6QyWTw9fVFbGwsnn322Radb/PmzXjttddMGySRFZNw6VuijuWLL77Ao48+igMHDiA6Otrc4TTL8ePHAQBhYWHtfu3KykqMHz8ev/32Gx544AHcc8898PPzw7Vr1/Drr79i1apVWLt2Le6+++52j82SKZVKZGRkaG2bOXMmSkpKsHr1aq3tgwYNgkwma/G1zp07h9LSUgwaNKjZx167dg3nzp1rdQwtsWnTJtx1110YOXIk/vnPf8Lf3x8KhQIHDx7Et99+i0uXLjX7nLNmzcJHH30E/hNOdJOtuQMgoo5JCIHKyko4OjoafYw5Etk6c+fOxZYtW/Dll19i8uTJWvvuvfdePP/886ioqDDJtW7cuAEnJyeTnMvcZDIZhg0bprXNzc0NVVVVOtsbqqioaNbfR0hISItiBIAuXbqgS5cuLT6+NRYtWoTg4GBs2bIFtrZ//bP7wAMPYNGiRWaJiaijYckBUSd15swZTJw4ET4+PpDJZAgNDcVHH32k1aayshLPPvssBg4cCLlcDk9PT8TGxuLHH3/UOZ9EIsGsWbPw8ccfIzQ0FDKZDF9++aXmp96tW7fiiSeegLe3N7y8vHDvvffiypUrWudoWHJQ93P2u+++iyVLliA4OBguLi6IjY3F3r17dWL49NNP0adPH8hkMoSFheGbb74x6mfq3NxcfPbZZxg9erROMlund+/eiIyMBGD45+tt27ZBIpFg27ZtWu8pPDwcO3bsQFxcHJycnPDYY49h/PjxCAoK0lvGEBMTg8GDB2teCyGQkpKCgQMHwtHRER4eHrjvvvtw/vz5Rt9XnZ07d2LUqFFwdXWFk5MT4uLisGnTJq02zfmcWqJHjx4YN24cNmzYgEGDBsHBwQGvv/46AOCjjz7CiBEj4OPjA2dnZ0RERGDRokWorq7WOoe+z7Lu7+6rr75CaGgonJycMGDAAPz8889631/9z6zuszlw4AASEhLg5OSEnj17YuHChTqfy7Fjx5CUlAQnJyd06dIFTz75JDZt2qTzeetTUFAAb29vrWS2jo2N7j/Da9euRWxsLJydneHi4oLRo0drjYJPmTJF8/9VU5Z0EFkzJrREndDx48cxZMgQHD16FIsXL8bPP/+MsWPHYvbs2ZokA7j5c3JhYSGee+45/PDDD1izZg2GDx+Oe++9F6tWrdI57w8//IBly5bhlVdewZYtW5CQkKDZN23aNNjZ2eGbb77BokWLsG3bNjz88MNGxfvRRx8hNTUVS5cuxerVq1FeXo477rgDJSUlmjbLly/H448/jsjISGzYsAEvv/wyXn/99SaTDQDYunUrqqurMX78eKPiaS6FQoGHH34YEydOxObNmzFz5kw89thjyM7Oxh9//KHV9uTJk9i/fz8effRRzbbp06djzpw5uO222/DDDz8gJSUFx44dQ1xcHK5evdrotbdv345bb70VJSUl+Pzzz7FmzRq4urrizjvvxNq1a3Xat+ZzasqhQ4fw/PPPY/bs2fj111/x97//HcDNUoKJEyfiq6++ws8//4ypU6finXfewfTp040676ZNm/Dhhx9iwYIFWL9+PTw9PXHPPfcYlfDn5ubioYcewsMPP4yNGzdizJgxmDdvHr7++mtNG4VCgcTERJw6dQrLli3DqlWrUFZWhlmzZhkVX2xsLPbt24fZs2dj3759Ool6fW+99RYefPBBhIWF4b///S+++uorlJWVISEhQVOS8+9//xv33XcfAGDPnj2ah7+/v1HxEHVIgog6lJUrVwoA4sCBAwbbjB49WnTr1k2UlJRobZ81a5ZwcHAQhYWFeo9TqVSiurpaTJ06VQwaNEhrHwAhl8t1jq2LZ+bMmVrbFy1aJAAIhUKh2ZaYmCgSExM1r7OysgQAERERIVQqlWb7/v37BQCxZs0aIYQQNTU1ws/PT8TExGhd4+LFi8LOzk4EBQUZ7AshhFi4cKEAIH799ddG2zV8T1lZWVrbt27dKgCIrVu3ar0nAOJ///ufVtvq6mrh6+srJk6cqLX9hRdeEPb29iI/P18IIcSePXsEALF48WKtdjk5OcLR0VG88MILjcY6bNgw4ePjI8rKyjTbVCqVCA8PF926dRNqtVrrPRnzOTUlMTFR9O/fX2tbUFCQkEql4tSpU40eW1NTI6qrq8WqVauEVCrV+nt65JFHdD5LAMLX11eUlpZqtuXm5gobGxuRnJys2abvM6v7bPbt26d1zrCwMDF69GjN6+eff15IJBJx7NgxrXajR4/W+bz1yc/PF8OHDxcABABhZ2cn4uLiRHJystbnkp2dLWxtbcVTTz2ldXxZWZnw8/MT999/v2bbk08+KfhPONFfOEJL1MlUVlbif//7H+655x44OTlBpVJpHnfccQcqKyu1fs5ft24d4uPj4eLiAltbW9jZ2eHzzz/HiRMndM596623wsPDQ+9177rrLq3XdT/fX7x4scmYx44dC6lUavDYU6dOITc3F/fff7/Wcd27d0d8fHyT529rHh4euPXWW7W22dra4uGHH8aGDRs0I801NTX46quvcPfdd8PLywsA8PPPP0MikeDhhx/W+qz8/PwwYMCARkegy8vLsW/fPtx3331wcXHRbJdKpZg0aRIuXbqEU6dOaR3Tms+pKZGRkejTp4/O9oyMDNx1113w8vKCVCqFnZ0dJk+ejJqaGpw+fbrJ895yyy1wdXXVvPb19YWPj49RMfv5+WHo0KE6cdY/dvv27QgPD9ep8X7wwQebPD8AeHl5IS0tDQcOHMDChQtx99134/Tp05g3bx4iIiKQn58PANiyZQtUKhUmT56s9Vk7ODggMTHRqF8biDorJrREnUxBQQFUKhU++OAD2NnZaT3uuOMOAND8A7thwwbcf//96Nq1K77++mvs2bMHBw4cwGOPPYbKykqdczf2k2ddglan7k5zY260aurYgoICADcTmYb0bWuoe/fuAICsrKwm27aEoX6p68dvv/0WwM2ERqFQaJUbXL16FUII+Pr66nxee/fu1XxW+hQVFUEIoff6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lposqTWUkjaWqtrWvrcak0RARERE1Lm1emGFhslsZWUlIiIi0EXPYgINeXt7QyqV6ozG5uXl6YzaNmbYsGE4c+aMwf0ymQxubm5aD1PxMrDEre747F+yKisBAOvy8kwWBxEREVFn1eKEdu3atUhJSdG8Pnv2LMLCwuDs7IyEhAQUFRU1eQ57e3tERUUhNTVVa3tqaqpmSjBjZGRkwN/f3/jgTcjTQEI72sOjyWMXX7qELM50QERERNQqLU5o3333XZSXl2teP//88ygqKsLTTz+NkydP4q233jLqPHPnzsVnn32GFStW4MSJE3jmmWeQnZ2NGTNmALhZLjB58mRN+6VLl+KHH37AmTNncOzYMcybNw/r16/HrFmzWvpWWu18TIzOtn7OzkYdu8JArTARERERGafFNbTnz59HeHg4gJtlBlu2bMHHH3+MyZMno2/fvnj33XfxzjvvNHmeCRMmoKCgAAsWLIBCoUB4eDg2b96MoKAgAIBCodCak7aqqgrPPfccLl++DEdHR/Tv3x+bNm3CHXfc0dK30mrBjo54o0cP/PvChWYf2+qaDyIiIqJOTiKMnTC2AUdHR2zZsgUjRozA9u3bceuttyI3NxddunRBWloaRo8ejRs3bpg6XpMoLS2FXC5HSUmJyeppC6ur4bVrl+a1GDnSYFvJtm2a51P8/LCyXz+TxEBERETUUTQnX2vxAKG/vz8yMzMBAL/++iv69u2ruRGsqKgITk5OLT21VfKwbdlg97WqKhNHQkRERNS5tLjk4N5778X8+fOxfft2/PLLL3jxxRc1+w4fPoyQBosIdHQSiQQuUimu1zRvMq5NhYVtFBERERFR59DihPaNN97A9evXsXv3bkycOBEvvPCCZt/PP/+M2267zSQBWpMRcjk2tyBBVQsBGy6DS0RERNQiLU5oHR0d8fHHH+vdt3fv3hYHZM2MTUk/6NULT509q3mdef06Bru6tk1QRERERB2cSW6yP336NPbs2dPo4gadQZWR99c92bWr1ms1l8AlIiIiarFWJbTr1q1DUFAQQkNDMXz4cPTr1w9BQUH47rvvTBWfVXmqNlH9W4PV0xpquKxvsUrVZjERERERdXQtTmg3b96MBx54AHK5HAsXLsSqVauQnJwMuVyOBx54AL/88osp47QKd3p742xMDDbWzs9rrAUXL7ZRREREREQdX4vn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ao5RKBR4+OGH8cILL+Ctt96CjY0NLly4gLFjxyIhIQErVqyAu7s7Ll++jF9//RVVVVVwcnJq9/dMRNQaTGiJiCxMSEiIJikdNmyY1r69e/fi008/xeLFizF37lzN9oSEBPTp0wdLlizB22+/rdleWFiIdevW4dZbb9VsW79+PSorK/HOO+9gwIABmu0TJ05sq7dERNSmWHJARGRFfv75Z0gkEjz88MNQqVSah5+fHwYMGIBt27Zptffw8NBKZgFg4MCBsLe3x+OPP44vv/xSp1SBiMjaMKElIrIiV69ehRACvr6+sLOz03rs3bsX+fn5Wu3ryhTqCwkJwe+//w4fHx88+eSTCAkJQUhICN5///32ehtERCbFkgMiIivi7e0NiUSCtLQ0yGQynf0Nt0kkEr3nSUhIQEJCAmpqanDw4EF88MEHmDNnDnx9ffHAAw+0SexERG2FI7RERBaoLjGtqKjQ2j5u3DgIIXD58mVER0frPCIiIpp1HalUipiYGM2sCocOHTLNGyAiakccoSUiskB1ienbb7+NMWPGQCqVIjIyEvHx8Xj88cfx6KOP4uDBgxgxYgScnZ2hUCiwc+dORERE4Iknnmj03B9//DH++OMPjB07Ft27d0dlZSVWrFgBALjtttva/L0REZkaE1oiIgs0ceJE7Nq1CykpKViwYAGEEMjKykKPHj3wySefYNiwYfjkk0+QkpICtVqNgIAAxMfHY+jQoU2ee+DAgfjtt9/w6quvIjc3Fy4uLggPD8fGjRuRlJTUDu+OiMi0JEIIYe4giIiIiIhaijW0RERERGTVmNASERERkVVjQktEREREVo0JLRERERFZNSa0RERERGTVmNASERERkVVjQktEREREVo0JLRERERFZNSa0RERERGTVmNASERERkVVjQktEREREVu3/AdUoyOjMERF2AAAAAElFTkSuQmCC",
            "text/plain": [
              "<Figure size 800x400 with 1 Axes>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "image/png": "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",
            "text/plain": [
              "<Figure size 800x400 with 1 Axes>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Test set:\n"
          ]
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "100%|███████████████████████████████████████████████████████████████████████████████████████████████████| 15/15 [00:23<00:00,  1.57s/it]\n"
          ]
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Avg Regret: 11.2376\n",
            "Avg Rel Regret: 47.51%\n",
            "Path Accuracy: 88.56%\n",
            "Optimality Ratio: 7.20%\n"
          ]
        }
      ],
      "source": [
        "# plot\n",
        "plotLearningCurve(loss_log5, regret_log5)\n",
        "# eval\n",
        "print(\"Test set:\")\n",
        "df5 = evaluate(nnet, optmodel, loader_test)"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "provenance": []
    },
    "kernelspec": {
      "display_name": "fpo-dys-env",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.9.6"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}
